[bzoj3531][Sdoi2014][旅行] (主席树+树链剖分)
Description
S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教, S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
Input
输入的第一行包含整数N,Q依次表示城市数和事件数。
接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
接下来N-1行每行两个整数x,y表示一条双向道路。
接下来Q行,每行一个操作,格式如上所述。
Output
对每个QS和QM事件,输出一行,表示旅行者记下的数字。
Sample Input
5 6 3 1 2 3 1 2 3 3 5 1 1 2 1 3 3 4 3 5 QS 1 5 CC 3 1 QS 1 5 CW 3 3 QS 1 5 QM 2 4
Sample Output
8 9 11 3
HINT
N,Q < =10^5 , C < =10^5
数据保证对所有QS和QM事件,起点和终点城市的信仰相同;在任意时
刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。
Solution
水题
用主席树做一做就好
#include <stdio.h> #include <string.h> #define RG register #define N 100010 #define dmax(a,b) ((a)>(b)?(a):(b)) template<class Type> inline void R(RG Type &x) { RG int c=getchar();for(;c<48||c>57;c=getchar()); for(x=0;c>47&&c<58;x=(x<<1)+(x<<3)+c-48,c=getchar()); } bool vis[N];int n,q,w[N],c[N],tim,fa[N],dep[N],sz[N],lef[N],top[N],hso[N],tot,root[N]; struct Pt { int v; Pt *nt; }*fi[N],me[N<<1],*tp=me; struct Ch { int ls,rs,mx,su; }tr[N*40]; inline void link(RG int x,RG int y) { *++tp=(Pt){y,fi[x]},fi[x]=tp; *++tp=(Pt){x,fi[y]},fi[y]=tp; } void dfsi(RG int x){ vis[x]=sz[x]=1; for(RG Pt *it=fi[x];it;it=it->nt) if(!vis[it->v]) dep[it->v]=dep[x]+1, fa[it->v]=x, dfsi(it->v), sz[x]+=sz[it->v], hso[x]=sz[it->v]>sz[hso[x]]?it->v:hso[x]; } void dfsm(RG int x){ vis[x]=0; top[x]=x==hso[fa[x]]?top[fa[x]]:x; lef[x]=++tim; if(hso[x]){ dfsm(hso[x]); for(RG Pt *it=fi[x];it;it=it->nt) if(vis[it->v]) dfsm(it->v); } } inline int lca(RG int x,RG int y){ while(top[x]^top[y]) dep[top[x]]>dep[top[y]]? x=fa[top[x]]: y=fa[top[y]]; return dep[x]<dep[y]?x:y; } inline void Pu(RG int pr) { tr[pr].mx=dmax(tr[tr[pr].ls].mx,tr[tr[pr].rs].mx); tr[pr].su=tr[tr[pr].ls].su+tr[tr[pr].rs].su; } void modify(RG int &pr,RG int x,RG int y,RG int po,RG int nu){ if(!pr)pr=++tot; if(!(x^y)) {tr[pr].mx=tr[pr].su=nu; return; } RG int mid=x+y>>1; if(po<=mid)modify(tr[pr].ls,x,mid,po,nu); else modify(tr[pr].rs,mid+1,y,po,nu); Pu(pr); } int qmx(RG int pr,RG int x,RG int y,RG int u,RG int v){ if(!pr)return 0; if(x==u&&y==v)return tr[pr].mx; RG int mid=x+y>>1; if(v<=mid)return qmx(tr[pr].ls,x,mid,u,v); if(u>mid)return qmx(tr[pr].rs,mid+1,y,u,v); return dmax(qmx(tr[pr].ls,x,mid,u,mid),qmx(tr[pr].rs,mid+1,y,mid+1,v)); } int qsm(RG int pr,RG int x,RG int y,RG int u,RG int v){ if(!pr)return 0; if(x==u&&y==v)return tr[pr].su; RG int mid=x+y>>1; if(v<=mid)return qsm(tr[pr].ls,x,mid,u,v); if(u>mid)return qsm(tr[pr].rs,mid+1,y,u,v); return qsm(tr[pr].ls,x,mid,u,mid)+qsm(tr[pr].rs,mid+1,y,mid+1,v); } inline int solvem(RG int col,RG int x,RG int f){ int re=0; while(top[x]^top[f]) re=dmax(re,qmx(root[col],1,n,lef[top[x]],lef[x])),x=fa[top[x]]; re=dmax(re,qmx(root[col],1,n,lef[f],lef[x])); return re; } inline int solves(int col,int x,int f){ int re=0; while(top[x]^top[f]) re+=qsm(root[col],1,n,lef[top[x]],lef[x]),x=fa[top[x]]; re+=qsm(root[col],1,n,lef[f],lef[x]); return re; } int main(){ RG char si[10];R(n),R(q); for(RG int i=1;i<=n;i++)R(w[i]),R(c[i]); for(RG int i=1,x,y;i<n;i++)R(x),R(y),link(x,y); dfsi(1),dfsm(1); for(RG int i=1;i<=n;i++)modify(root[c[i]],1,n,lef[i],w[i]); for(int x,y,t,tmp;q;q--){ scanf("%s",si),R(x),R(y); if(si[0]=='C'&&si[1]=='C') modify(root[c[x]],1,n,lef[x],0), c[x]=y, modify(root[c[x]],1,n,lef[x],w[x]); if(si[0]=='C'&&si[1]=='W') modify(root[c[x]],1,n,lef[x],y),w[x]=y; if(si[0]=='Q'&&si[1]=='S') t=lca(x,y),tmp=solves(c[x],x,t)+solves(c[x],y,t),c[x]==c[t]?tmp-=w[t]:1,printf("%d\n",tmp); if(si[0]=='Q'&&si[1]=='M') t=lca(x,y),printf("%d\n",dmax(solvem(c[x],x,t),solvem(c[x],y,t))); } return 0; }