[WC2013]糖果公園 (樹上帶修莫隊)

 

 

題解

首先我們發現喫糖的順序是不會影響答案的

影響答案的是每種糖的個數

所以我們可以直接利用樹上莫隊來做

樹上莫隊有兩種寫法,一種是在括號序列上進行莫隊,另一種就直接對樹進行分塊,在樹上進行莫隊

這裏寫的是在括號序列上的莫隊

如何帶修改呢

我們維護一種有三個指針的莫隊(比普通的莫隊多一個時間指針)

類似普通的莫隊一樣移動指針就可以了

只不過塊的大小要調爲n^(2/3)

具體的時間複雜度分析可以看這篇博客

代碼:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 200005
#define LL long long
int fir[N],to[N],nxt[N],cnt;
void adde(int a,int b)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int fa[N],siz[N],top[N],son[N],dep[N];
int L[N],R[N],pos[N],dc;
void dfs1(int u)
{
	siz[u]=1;dep[u]=dep[fa[u]]+1;
	for(int v,p=fir[u];p;p=nxt[p]){
		if((v=to[p])!=fa[u]){
			fa[v]=u;dfs1(v);
			siz[u]+=siz[v];
			if(siz[son[u]]<siz[v])
				son[u]=v;
		}
	}
}
void dfs2(int u)
{
	L[u]=++dc;pos[dc]=u;
	if(son[u])top[son[u]]=top[u],dfs2(son[u]);
	for(int v,p=fir[u];p;p=nxt[p])
		if((v=to[p])!=fa[u]&&v!=son[u])
			top[v]=v,dfs2(v);
	R[u]=++dc;pos[dc]=u;
}
int LCA(int x,int y)
{
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
int bel[N],cha[N][3],tcnt,qcnt;
struct node{
	int l,r,t,id;
	bool operator < (const node &T)const{
		return bel[l]==bel[T.l] ? ( bel[r]==bel[T.r] ? (((bel[l]^bel[r])&1)?t<T.t:t>T.t) : ((bel[l]&1)?bel[r]<bel[T.r]:bel[r]>bel[T.r]) ) : bel[l]<bel[T.l];
	}
}q[N];
LL ans[N],sum;
int V[N],W[N],C[N],con[N];bool vis[N];
void update(int x)
{
	if(vis[x])sum-=1ll*V[C[x]]*(W[con[C[x]]--]);
	else sum+=1ll*V[C[x]]*(W[++con[C[x]]]);
	vis[x]^=1;
}
void modify(int x,int y)
{
	if(vis[x]){update(x);C[x]=y;update(x);}
	else C[x]=y;
}
int tmpC[N];
int main()
{
	int n,m,Q,i,u,v,op;
	n=gi();m=gi();Q=gi();
	for(i=1;i<=m;i++)V[i]=gi();
	for(i=1;i<=n;i++)W[i]=gi();
	for(i=1;i<n;i++){u=gi();v=gi();adde(u,v);}
	dfs1(1);top[1]=1;dfs2(1);
	for(i=1;i<=n;i++)tmpC[i]=C[i]=gi();
	for(i=1;i<=Q;i++){
		op=gi();u=gi();v=gi();
		if(op==0){
			cha[++tcnt][0]=u;
			cha[tcnt][1]=v;
			cha[tcnt][2]=tmpC[u];
			tmpC[u]=v;
		}
		else{
			if(L[u]>L[v])swap(u,v);
			int lca=LCA(u,v);
			q[++qcnt].l=(lca==u?L[u]:R[u]);
			q[qcnt].r=L[v];
			q[qcnt].t=tcnt;
			q[qcnt].id=qcnt;
		}
	}
	int D=pow(2.0*n,0.6666);
	for(i=1;i<=2*n;i++)bel[i]=(i-1)/D+1;
	sort(q+1,q+qcnt+1);
	int l=1,r=0,t=0;
	for(i=1;i<=qcnt;i++){
		while(t<q[i].t)t++,modify(cha[t][0],cha[t][1]);
		while(t>q[i].t)modify(cha[t][0],cha[t][2]),t--;
		while(l>q[i].l)l--,update(pos[l]);
		while(r<q[i].r)r++,update(pos[r]);
		while(l<q[i].l)update(pos[l]),l++;
		while(r>q[i].r)update(pos[r]),r--;
		int lca=LCA(pos[q[i].l],pos[q[i].r]);
		if(lca!=pos[q[i].l])update(lca);
		ans[q[i].id]=sum;
		if(lca!=pos[q[i].l])update(lca);
	}
	for(i=1;i<=qcnt;i++)
		printf("%lld\n",ans[i]);
}

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章