#树上带修莫队,树链剖分#洛谷 4074 [WC2013]糖果公园

题目


分析

考虑将树转换成序列求解,那就用欧拉序,入栈一次出栈一次正好抵消掉
注意当起点不是LCA的时候要将起点加入,剩下就是带修莫队板子题了


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm> 
#define rr register
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2?EOF:*p1++)
using namespace std;
char buf[1<<21],puf[1<<21],*p1,*p2; int nowp=-1;
const int N=100011; typedef long long lll; struct rec{int x,y;}cha[N];
struct node{int y,next;}e[N<<1]; struct four{int l,r,now,rk;}q[N];
int dep[N],c[N],dfn[N],nfd[N<<1],Top[N],Q; lll w[N],now,ans[N]; bool v[N];
int siz[N],fat[N],big[N],n,Cnt[N],col[N],et=1,as[N],tot,bl,NOW,QQ,m,kuai[N<<1];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void Flush(){fwrite(puf,1,nowp+1,stdout),nowp=-1;}
inline void Putchar(char x){
	if (nowp==(1<<21)) Flush();
	puf[++nowp]=x;
}
inline void print(lll ans){
	rr char dig[21]; rr int len=-1;
	if (ans<0) Putchar('-'),ans=-ans;
	do{
		dig[++len]=ans%10+48,ans/=10; 
	}while (ans);
	while (len>=0) Putchar(dig[len--]);
}
inline void dfs1(int x,int fa){
	dep[x]=dep[fa]+1,fat[x]=fa,siz[x]=1;
	for (rr int i=as[x],SIZ=-1;i;i=e[i].next)
	if (e[i].y!=fa){
		dfs1(e[i].y,x),siz[x]+=siz[e[i].y];
		if (siz[e[i].y]>SIZ) big[x]=e[i].y,SIZ=siz[e[i].y];
	}
}
inline void dfs2(int x,int linp){
	nfd[dfn[x]=++tot]=x,Top[x]=linp;
	if (big[x]) dfs2(big[x],linp);
	for (rr int i=as[x];i;i=e[i].next)
	if (e[i].y!=fat[x]&&e[i].y!=big[x])
	    dfs2(e[i].y,e[i].y);
	nfd[++tot]=x;
}
inline signed Lca(int x,int y){
	while (Top[x]!=Top[y]){
		if (dep[Top[x]]<dep[Top[y]]) x^=y,y^=x,x^=y;
		x=fat[Top[x]];
	}
	if (dep[x]>dep[y]) x^=y,y^=x,x^=y;
	return x;
}
bool cmp(four a,four b){
    if (kuai[a.l]^kuai[b.l]) return a.l<b.l;
    if (kuai[a.r]^kuai[b.r]) return kuai[a.l]&1?a.r<b.r:a.r>b.r;
    return (kuai[a.l]^kuai[a.r])&1?a.now<b.now:a.now>b.now;
}
inline void doit(int x){
	v[x]^=1;
	if (v[x]) now+=w[++Cnt[col[x]]]*c[col[x]];
	    else now-=w[Cnt[col[x]]--]*c[col[x]];
}
inline void update(int Now){
	rr int x=cha[Now].x,Y=cha[Now].y,X=col[x];
	if (v[x]) now+=w[++Cnt[Y]]*c[Y]-w[Cnt[X]--]*c[X];
    col[x]=Y,cha[Now].y=X;
}
signed main(){
	n=iut(),m=iut(),QQ=iut();
	for (rr int i=1;i<=m;++i) c[i]=iut();
	for (rr int i=1;i<=n;++i) w[i]=iut();
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut();
		e[++et]=(node){y,as[x]},as[x]=et;
		e[++et]=(node){x,as[y]},as[y]=et;
	}
	for (rr int i=1;i<=n;++i) col[i]=iut();
	dfs1(1,0),dfs2(1,1);
	for (;QQ;--QQ){
		rr int typ=iut(),x=iut(),y=iut();
		if (typ){
			if (dfn[x]>dfn[y]) x^=y,y^=x,x^=y;
			q[++Q]=(four){dfn[x],dfn[y],NOW,Q};
		}else cha[++NOW]=(rec){x,y};
	}
	bl=pow(n,NOW?2.0/3:1.0/2);
	for (rr int i=1;i<=n*2;++i) kuai[i]=i/bl;
	rr int x,y,l,r,Z=0,z; sort(q+1,q+1+Q,cmp);
	for (rr int i=1,L=q[1].l,R=L-1;i<=Q;++i){
		x=nfd[l=q[i].l],y=nfd[r=q[i].r],z=q[i].now;
		while (L>l) doit(nfd[--L]);
		while (L<l) doit(nfd[L++]);
		while (R>r) doit(nfd[R--]);
		while (R<r) doit(nfd[++R]);
		while (Z>z) update(Z--);
		while (Z<z) update(++Z);
		rr int lca=Lca(x,y);
		if (x^lca) doit(x),doit(lca);
		ans[q[i].rk]=now;
		if (x^lca) doit(x),doit(lca);
	}
	for (rr int i=1;i<=Q;++i) print(ans[i]),Putchar(10);
	Flush();
	return 0;
} 
posted @ 2020-10-03 02:32  lemondinosaur  阅读(80)  评论(0编辑  收藏  举报