正题
我不喜欢旅行对不起
看到题目,就会知道有三个东西要维护,一个是路径,一个是评级,一个是宗教。
主要是宗教和评级之间的关系,要取路径上宗教为某个特定值的评级最大值或和。
想到用树链剖分来进行重新编号,使得一条重链上的编号连续,然后对于每一个评级,我们开一棵主席树(动态开点线段树无优化)。那么可以节省下来很多空间。
然后树链剖分来进行操作并统计答案即可。
修改宗教和评级相当于就是换根(到另一个宗教的主席树内)和底层信息(向上维护最大值和总和)。
代码<比较简单这题>
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; int n,m; int w[200010],c[200010]; struct edge{ int y,next; }s[200010]; int first[200010]; int len=0; int fa[200010],image[200010],fact[200010],dep[200010],tot[200010],son[200010],top[200010]; int mmax[20000010]; int total[20000010]; int ls[20000010],rs[20000010]; int root[200010]; int tx,ty; int x,y; int d,v; int ans,op; void ins(int x,int y){ len++; s[len].y=y;s[len].next=first[x];first[x]=len; } void dfs_1(int x){ tot[x]=1; for(int i=first[x];i!=0;i=s[i].next){ int y=s[i].y; if(y!=fa[x]){ dep[y]=dep[x]+1; fa[y]=x; dfs_1(y); if(tot[son[x]]<tot[y]) son[x]=y; tot[x]+=tot[y]; } } } void dfs_2(int x,int tp){ top[x]=tp;image[x]=++len;fact[len]=x; if(son[x]!=0) dfs_2(son[x],tp); for(int i=first[x];i!=0;i=s[i].next){ int y=s[i].y; if(y!=fa[x] && y!=son[x]) dfs_2(y,y); } } void update(int &now,int l,int r){ if(now==0) now=++len; total[now]+=d; if(l==r) { if(d>0) mmax[now]=d; else mmax[now]=0; return ; } if(v<=(l+r)/2) update(ls[now],l,(l+r)/2); else update(rs[now],(l+r)/2+1,r); mmax[now]=max(mmax[ls[now]],mmax[rs[now]]); } void change_c(){ scanf("%d %d",&x,&y); v=image[x];d=-w[x]; update(root[c[x]],1,n); c[x]=y;d=w[x]; update(root[c[x]],1,n); } void change_w(){ scanf("%d %d",&x,&y); v=image[x];d=-w[x]; update(root[c[x]],1,n); w[x]=y;d=w[x]; update(root[c[x]],1,n); } int query_sum(int now,int l,int r,int x,int y){ if(x==l && y==r) return total[now]; if(r<=(x+y)/2) return query_sum(ls[now],l,r,x,(x+y)/2); else if((x+y)/2<l) return query_sum(rs[now],l,r,(x+y)/2+1,y); else return query_sum(ls[now],l,(x+y)/2,x,(x+y)/2)+query_sum(rs[now],(x+y)/2+1,r,(x+y)/2+1,y); } int get_sum(){ scanf("%d %d",&x,&y); op=x; tx=top[x],ty=top[y]; ans=0; while(tx!=ty){ if(dep[tx]>dep[ty]){ swap(x,y);swap(tx,ty); } ans+=query_sum(root[c[op]],image[ty],image[y],1,n); y=fa[ty];ty=top[y]; } if(dep[x]>dep[y]) swap(x,y); ans+=query_sum(root[c[op]],image[x],image[y],1,n); return ans; } int query_max(int now,int l,int r,int x,int y){ if(x==l && y==r) return mmax[now]; if(r<=(x+y)/2) return query_max(ls[now],l,r,x,(x+y)/2); else if((x+y)/2<l) return query_max(rs[now],l,r,(x+y)/2+1,y); else return max(query_max(ls[now],l,(x+y)/2,x,(x+y)/2),query_max(rs[now],(x+y)/2+1,r,(x+y)/2+1,y)); } int get_max(){ scanf("%d %d",&x,&y); op=x; tx=top[x],ty=top[y]; ans=0; while(tx!=ty){ if(dep[tx]>dep[ty]){ swap(x,y);swap(tx,ty); } ans=max(ans,query_max(root[c[op]],image[ty],image[y],1,n)); y=fa[ty];ty=top[y]; } if(dep[x]>dep[y]) swap(x,y); ans=max(ans,query_max(root[c[op]],image[x],image[y],1,n)); return ans; } int main(){ scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) scanf("%d %d",&w[i],&c[i]); for(int i=1;i<=n-1;i++){ scanf("%d %d",&x,&y); ins(x,y); ins(y,x); } dep[1]=1;tot[1]=0;son[1]=0;fa[1]=0;dfs_1(1); len=0;dfs_2(1,1); len=0; for(int i=1;i<=n;i++){ v=image[i];d=w[i]; update(root[c[i]],1,n); } char ch[10]; while(m--){ scanf("%s",ch); if(ch[1]=='C') change_c(); else if(ch[1]=='W') change_w(); else if(ch[1]=='S') printf("%d\n",get_sum()); else if(ch[1]=='M') printf("%d\n",get_max()); } }