【提示】您已获得新技能:动态开点线段树
这道题,如果没有只能留宿于信仰相同的城市这个规定,显然是用树剖瞎搞一通,再用线段树瞎搞一通。
现在有了宗教信仰的规定,很容易想到的一个思路是对于每个宗教开一棵线段树。但是这样空间会GG,所以又想到动态开点线段树。
所谓动态开点线段树,就是你的编号不能和普通线段树一样,x的儿子是 x∗2 x ∗ 2 和 x∗2+1 x ∗ 2 + 1 ,而应该新编号。除此之外,和普通线段树没有什么区别。
做完这道题后,可以去查查有关飞天面条神教,隐形独角兽教和绝地教的百度百科辣
#include
using namespace std;
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
const int N=100005,M=5000005;
int n,Q,tot,SZ,now;
int h[N],ne[N<<1],to[N<<1],c[N],w[N];
int top[N],sz[N],f[N],pos[N],dep[N],rt[N];
void add(int x,int y) {to[++tot]=y,ne[tot]=h[x],h[x]=tot;}
void dfs1(int x,int las) {//树剖
f[x]=las,sz[x]=1,dep[x]=dep[las]+1;
for(int i=h[x];i;i=ne[i])
if(to[i]!=las) dfs1(to[i],x),sz[x]+=sz[to[i]];
}
void dfs2(int x,int las) {
int mx=0,bj=0; pos[x]=++now;
for(int i=h[x];i;i=ne[i])
if(to[i]!=las&&mxif(!bj) return;
top[bj]=top[x],dfs2(bj,x);
for(int i=h[x];i;i=ne[i])
if(to[i]!=las&&to[i]!=bj) top[to[i]]=to[i],dfs2(to[i],x);
}
int sum[M],mx[M],ls[M],rs[M];
void up(int x){
sum[x]=sum[ls[x]]+sum[rs[x]],mx[x]=max(mx[ls[x]],mx[rs[x]]);
}
void chan(int &x,int s,int t,int mb,int num) {//动态加入新点
if(!x) x=++SZ;//开个新点
if(s==t) {sum[x]=mx[x]=num;return;}
int mid=(s+t)>>1;
if(mb<=mid) chan(ls[x],s,mid,mb,num);
else chan(rs[x],mid+1,t,mb,num);
up(x);
}
int getmx(int x,int l,int r,int s,int t) {
if(l<=s&&t<=r) return mx[x];
int mid=(s+t)>>1,re=0;
if(l<=mid) re=getmx(ls[x],l,r,s,mid);
if(mid+1<=r) re=max(re,getmx(rs[x],l,r,mid+1,t));
return re;
}
int getsum(int x,int l,int r,int s,int t) {
if(l<=s&&t<=r) return sum[x];
int mid=(s+t)>>1,re=0;
if(l<=mid) re=getsum(ls[x],l,r,s,mid);
if(mid+1<=r) re+=getsum(rs[x],l,r,mid+1,t);
return re;
}
void work(int x,int y,int flag) {//获得答案
int re=0,cx=c[x];
while(top[x]!=top[y]) {
if(dep[top[x]]if(flag) re=max(re,getmx(rt[cx],pos[top[x]],pos[x],1,n));
else re+=getsum(rt[cx],pos[top[x]],pos[x],1,n);
x=f[top[x]];
}
if(pos[x]>pos[y]) swap(x,y);
if(flag) re=max(re,getmx(rt[cx],pos[x],pos[y],1,n));
else re+=getsum(rt[cx],pos[x],pos[y],1,n);
printf("%d\n",re);
}
int main()
{
int x,y;char ch[10];
n=read(),Q=read();
for(int i=1;i<=n;++i) w[i]=read(),c[i]=read();
for(int i=1;i1,0),top[1]=1,dfs2(1,0);
for(int i=1;i<=n;++i) chan(rt[c[i]],1,n,pos[i],w[i]);
while(Q--) {
scanf("%s",ch),x=read(),y=read();
if(ch[0]=='C'&&ch[1]=='C')
chan(rt[c[x]],1,n,pos[x],0),c[x]=y,chan(rt[y],1,n,pos[x],w[x]);
else if(ch[0]=='C'&&ch[1]=='W')
w[x]=y,chan(rt[c[x]],1,n,pos[x],w[x]);
else if(ch[0]=='Q'&&ch[1]=='S') work(x,y,0);
else work(x,y,1);
}
return 0;
}