[WC2013] 糖果公园

传送门

真是品鉴了一个大的。第一道树上莫队题。

题目思路

带修树上莫队。

还是随便放一点树上莫队的知识点吧。

利用欧拉序将树上路径变为序列,其中 \(st_u\) 是第一次出现位置,\(en_u\) 是第二次出现位置。

假设 \(st_x<st_y\)。令 \(ll=lca(x,y)\):

若 \(ll=u\),此时路径 \(u\) 到 \(v\) 对应欧拉序区间:\([ st_u, st_v ]\)。

否则对应欧拉序区间:\([ en_u, st_v ]\)。并且还要加上 \(ll\)。

维护莫队时,由于每个点出现两次,所以这个状态更新是类似于异或的:

void deal(int x){
	if(used[x])	remove(x);
	else	add(x);
	used[i]^=1;
}

大概就这么多。

回到这道题,好像也没什么难的嘛比较板子,就是还有修改。

🍭🍭错误:传参混淆;存欧拉序的数组忘两倍。

AC Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n,m,ln,q,v[N],w[N],fat[N][25],c[N],qcnt,rcnt,ans[N];
int st[N],en[N],tim,dth[N],tot,el[N<<2],EL,Cnt[N],cc[N];
bool vis[N];
vector<int>g[N];
struct node{
	int t,l,r,ex,id;
	bool operator < (const node& s1)const{
		if(s1.l/ln!=l/ln)	return l<s1.l;
		if(s1.r/ln!=r/ln)	return r<s1.r;
		return t<s1.t;
	}
}qr[N];
struct str{
	int w,ps,to;
}r[N];
void dfs(int u,int fa){
	fat[u][0]=fa;st[u]=++tim;el[++EL]=u;dth[u]=dth[fa]+1;
	for(int i=1;i<=24;i++)
		fat[u][i]=fat[fat[u][i-1]][i-1];
	for(int v:g[u]){
		if(v==fa)	continue;
		dfs(v,u);
	}
	en[u]=++tim;
	el[++EL]=u;
}
int lca(int x,int y){
	if(dth[x]<dth[y])	swap(x,y);
	for(int i=24;i>=0;i--){
		if(dth[x]-(1<<i)>=dth[y])	x=fat[x][i];
	}
	if(x==y)	return x;
	for(int i=24;i>=0;i--){
		if(fat[x][i]!=fat[y][i]){
			x=fat[x][i];y=fat[y][i];
		}
	}
	return fat[x][0];
}
void add(int x){
	Cnt[x]++;
	tot+=w[Cnt[x]]*v[x];
}
void del(int x){
	tot-=w[Cnt[x]]*v[x];
	Cnt[x]--;
}
void deal(int x){
	if(vis[x])	del(c[x]);
	else	add(c[x]);
	vis[x]^=1;
}
void hs(){
	sort(qr+1,qr+qcnt+1);
	for(int i=1,L=1,R=0,last=0;i<=qcnt;i++){ 
		while(L>qr[i].l)	deal(el[--L]);
		while(R<qr[i].r)	deal(el[++R]);	
		while(L<qr[i].l)	deal(el[L++]);
		while(R>qr[i].r)	deal(el[R--]);
		while(last<qr[i].t){
			last++;
			int x=r[last].w;
			if(vis[x]){
				del(c[x]);
				add(r[last].to);
			}
			c[x]=r[last].to;
		}
		while(last>qr[i].t){
			int x=r[last].w;
			if(vis[x]){
				del(c[x]);
				add(r[last].ps);
			}
			c[x]=r[last].ps;
			last--;
		}
		ans[qr[i].id]=tot;
		if(qr[i].ex!=0){
			Cnt[c[qr[i].ex]]++;
			ans[qr[i].id]+=v[c[qr[i].ex]]*w[Cnt[c[qr[i].ex]]];
			Cnt[c[qr[i].ex]]--;
		}
	}
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m>>q;
	ln=pow(n*2,2.0/3.0);
	for(int i=1;i<=m;i++)	cin>>v[i];
	for(int i=1;i<=n;i++)	cin>>w[i];
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)	cin>>c[i],cc[i]=c[i];
	for(int i=1,op,x,y,L=0,R=0,ex=0;i<=q;i++){
		cin>>op>>x>>y;
		if(op){
			//根据(x,y)算出L,R,ex
			if(st[x]>st[y])	swap(x,y);
			int ll=lca(x,y);
			if(x==ll){
				L=st[x];R=st[y];ex=0;	
			}
			else{
				L=en[x];R=st[y];ex=ll;
			}
			qcnt++;qr[qcnt]={rcnt,L,R,ex,qcnt};
		}
		else{
			r[++rcnt]={x,cc[x],y};
			cc[x]=y;
		}
	}
	hs();
	for(int i=1;i<=qcnt;i++)	cout<<ans[i]<<"\n";
	return 0;
}
posted @ 2026-10-08 11:43  深申  阅读(5)  评论(0)    收藏  举报