bzoj 3052: [wc2013]糖果公园【树上带修改莫队】

参考:http://blog.csdn.net/lych_cys/article/details/50845832
把树变成dfs括号序的形式,注意这个是不包含lca的(除非lca是两点中的一个)
然后把询问按照所属块一序,r二序,t三序排序(注意a和b数组的同名变量意思不一样),对于每个询问处理修改,时间正流或者逆流,修改答案时用vis数组记录这个位置是否在答案中被统计过来决定加减。对于修改序列的操作,如果他没有被统计在答案里就直接修改,否则修改答案。对lca特殊处理

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=200005;
int n,m,q,u[N],v[N],w[N],h[N],cnt,c[N],la[N],kuai,f[N],g[N],dfn,bl[N],cnta,cntb;
int de[N],fa[N],fr[N],si[N],hs[N],rl[N];
long long ans[N],sum;
bool vis[N];
struct qw
{
	int ne,to;
}e[N<<1];
struct qwe
{
	int l,r,t,rl;
}a[N],b[N];//对于b,l是位置,r是修改为的颜色,t是上一个颜色
bool cmp(qwe x,qwe y)
{
	return bl[x.l]<bl[y.l]||bl[x.l]==bl[y.l]&&bl[x.r]<bl[y.r]||bl[x.l]==bl[y.l]&&bl[x.r]==bl[y.r]&&x.t<y.t;
}
int read()
{
	int r=0;
	char p=getchar();
	while(p>'9'||p<'0')
		p=getchar();
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r;
}
void add(int u,int v)
{
	cnt++;
	e[cnt].ne=h[u];
	e[cnt].to=v;
	h[u]=cnt;
}
void dfs1(int u,int fat)
{
	fa[u]=fat;
	de[u]=de[fat]+1;
	si[u]=1;
	f[u]=++dfn;
	rl[dfn]=u;
	for(int i=h[u];i;i=e[i].ne)
		if(e[i].to!=fat)
		{
			dfs1(e[i].to,u);
			si[u]+=si[e[i].to];
			if(si[e[i].to]>si[hs[u]])
				hs[u]=e[i].to;
		}
	g[u]=++dfn;
	rl[dfn]=u;
}
void dfs2(int u,int top)
{
	fr[u]=top;
	if(!hs[u])
		return;
	dfs2(hs[u],top);
	for(int i=h[u];i;i=e[i].ne)
		if(e[i].to!=fa[u]&&e[i].to!=hs[u])
			dfs2(e[i].to,e[i].to);
}
int lca(int u,int v)
{
    for(;fr[u]!=fr[v];de[fr[u]]>de[fr[v]]?u=fa[fr[u]]:v=fa[fr[v]]);
    return de[u]>de[v]?v:u;
}
void add(int x)
{
	if(vis[x])
		sum-=(long long)v[c[x]]*w[u[c[x]]--];
	else
		sum+=(long long)v[c[x]]*w[++u[c[x]]];
	vis[x]^=1;
}
void change(int x,int y)
{
	if(vis[x])
	{
		add(x);
		c[x]=y;
		add(x);
	}
	else
		c[x]=y;
}
int main()
{
	n=read(),m=read(),q=read();
	for(int i=1;i<=m;i++)
		v[i]=read();
	for(int i=1;i<=n;i++)
		w[i]=read();
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		add(x,y);add(y,x);
	}
	for(int i=1;i<=n;i++)
		c[i]=la[i]=read();
	kuai=(int)pow(n,2.0/3);
	dfs1(1,0);
	dfs2(1,1);
	for(int i=1;i<=dfn;i++)
		bl[i]=(i-1)/kuai;
	while(q--)
	{
		int t=read(),l=read(),r=read();
		if(t==0)
		{
			b[++cntb].l=l;
			b[cntb].t=la[l];
			la[l]=b[cntb].r=r;
		}
		else
		{
			if(f[l]>f[r])
				swap(l,r);
			a[++cnta].r=f[r];
			a[cnta].rl=cnta;
			a[cnta].t=cntb;//cout<<lca(l,r)<<endl;
			a[cnta].l=(lca(l,r)==l)?f[l]:g[l];
		}
	}
	sort(a+1,a+cnta,cmp);
	int l=1,r=0,t=1;
	for(int i=1;i<=cnta;i++)
	{
		for(;t<=a[i].t;t++)
			change(b[t].l,b[t].r);
		for(;t>a[i].t;t--)
			change(b[t].l,b[t].t);
		while(l>a[i].l)
			add(rl[--l]);
		while(l<a[i].l)
			add(rl[l++]);
		while(r>a[i].r)
			add(rl[r--]);
		while(r<a[i].r)
			add(rl[++r]);
		int x=rl[l],y=rl[r],tmp=lca(x,y);//cout<<x<<" "<<y<<" "<<tmp<<endl;
		if(x!=tmp&&y!=tmp)
		{
			add(tmp);
			ans[a[i].rl]=sum;
			add(tmp);
		}
		else
			ans[a[i].rl]=sum;
	}
	for(int i=1;i<=cnta;i++)
		printf("%lld\n",ans[i]);
	return 0;
}
/*
4 3 5
1 9 2
7 6 5 1
2 3
3 1
3 4
1 2 3 2
1 1 2
1 4 2
0 2 1
1 1 2
1 4 2
*/
posted @ 2018-01-11 10:35  lokiii  阅读(222)  评论(0编辑  收藏  举报