树链剖分+动态开点的线段树
树剖好以后每个宗教建一棵线段树,把初始状态每个城市插入树中。
查询时边求LCA边在线段树中查询。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<Windows.h>
using namespace std;
int wi[100010],ci[100010],to[200010],nex[200010],head[100010];
int d[100010],son[100010],s[100010],fa[100010],rt[100010],cnt=1;
int top[100010],id[100010],rk[100010],n,qx,qy,qc;
struct node
{
int sum,m,l,r;
}tree[10000000];
void dfs1(int now,int deep)
{
d[now]=deep;
s[now]=1;
for(int i=head[now];i>0;i=nex[i])
{
if(to[i]==fa[now])
continue;
fa[to[i]]=now;
dfs1(to[i],deep+1);
s[now]+=s[to[i]];
if(s[to[i]]>s[son[now]])
son[now]=to[i];
}
}
void dfs2(int now,int t)
{
top[now]=t;
id[now]=++id[0];
rk[id[now]]=now;
if(!son[now])
return;
dfs2(son[now],t);
for(int i=head[now];i>0;i=nex[i])
{
if(to[i]==son[now]||to[i]==fa[now])
continue;
dfs2(to[i],to[i]);
}
}
void build(int l,int r,int &rt,int x,int w)
{
if(!rt)
rt=cnt++;
if(l==r)
{
tree[rt].sum+=w;
tree[rt].m=max(tree[rt].m,w);
return;
}
int mid=(l+r)>>1;
if(x<=mid)
build(l,mid,tree[rt].l,x,w);
else
build(mid+1,r,tree[rt].r,x,w);
tree[rt].sum=tree[tree[rt].l].sum+tree[tree[rt].r].sum;
tree[rt].m=max(tree[tree[rt].l].m,tree[tree[rt].r].m);
}
void change1(int l,int r,int &rt,int x)
{
/* if(!rt)
rt=cnt++;*/
if(l==r)
{
tree[rt].sum=0;
tree[rt].m=0;
return;
}
int mid=(l+r)>>1;
if(x<=mid)
change1(l,mid,tree[rt].l,x);
else
change1(mid+1,r,tree[rt].r,x);
tree[rt].sum=tree[tree[rt].l].sum+tree[tree[rt].r].sum;
tree[rt].m=max(tree[tree[rt].l].m,tree[tree[rt].r].m);
}
void change2(int l,int r,int &rt,int x,int w)
{
/*if(!rt)
rt=cnt++;*/
if(l==r)
{
tree[rt].sum=w;
tree[rt].m=w;
return;
}
int mid=(l+r)>>1;
if(x<=mid)
change2(l,mid,tree[rt].l,x,w);
else
change2(mid+1,r,tree[rt].r,x,w);
tree[rt].sum=tree[tree[rt].l].sum+tree[tree[rt].r].sum;
tree[rt].m=max(tree[tree[rt].l].m,tree[tree[rt].r].m);
}
int qs(int l,int r,int rt)
{
if(qx<=l&&r<=qy)
return tree[rt].sum;
int mid=(l+r)>>1,ans=0;
if(qx<=mid)
ans+=qs(l,mid,tree[rt].l);
if(qy>mid)
ans+=qs(mid+1,r,tree[rt].r);
return ans;
}
int qm(int l,int r,int rt)
{
if(qx<=l&&r<=qy)
return tree[rt].m;
int mid=(l+r)>>1,ans=0;
if(qx<=mid)
ans=max(ans,qm(l,mid,tree[rt].l));
if(qy>mid)
ans=max(ans,qm(mid+1,r,tree[rt].r));
return ans;
}
int lca(int x,int y,int h)
{
int ans=0;
while(top[x]!=top[y])
{
if(d[top[x]]>d[top[y]])
{
qx=id[top[x]];qy=id[x];
if(h)
ans+=qs(1,n,rt[qc]);
else
ans=max(ans,qm(1,n,rt[qc]));
x=fa[top[x]];
}
else
{
qx=id[top[y]];qy=id[y];
if(h)
ans+=qs(1,n,rt[qc]);
else
ans=max(ans,qm(1,n,rt[qc]));
y=fa[top[y]];
}
}
if(d[x]>d[y])swap(x,y);
qx=id[x];qy=id[y];
if(h)
ans+=qs(1,n,rt[qc]);
else
ans=max(ans,qm(1,n,rt[qc]));
return ans;
}
inline int read()
{
char c;
int re=0;
c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
{
re=re*10+c-'0';
c=getchar();
}
return re;
}
int main()
{
//freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
//DWORD startTime = GetTickCount();
int q,con=1;
n=read();q=read();
for(int i=1;i<=n;++i)
{wi[i]=read();ci[i]=read();}
for(int i=1;i<n;++i)
{
int a,b;
a=read();b=read();
to[con]=b;nex[con]=head[a];head[a]=con++;
to[con]=a;nex[con]=head[b];head[b]=con++;
}
fa[1]=1;
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=n;++i)
build(1,n,rt[ci[i]],id[i],wi[i]);
// build(1,n,1);
// int times=1;
for(int i=1;i<=q;++i)
{
int x,y;
char c,q;
c=getchar();
while(c!='C'&&c!='Q')
c=getchar();
q=getchar();
x=read();y=read();
if(c=='C')
{
if(q=='C')
{
change1(1,n,rt[ci[x]],id[x]);
ci[x]=y;
build(1,n,rt[ci[x]],id[x],wi[x]);
}
else
{
wi[x]=y;
change2(1,n,rt[ci[x]],id[x],y);
}
}
else
{
qc=ci[x];
if(q=='S')
printf("%d\n",lca(x,y,1));
else
printf("%d\n",lca(x,y,0));
/* if(times==479)
{
cout<<c<<q<<x<<' '<<y<<endl;
return 0;
}
times++;*/
}
}
/*DWORD endTime = GetTickCount();//¼ÆÊ±½áÊø
cout << "The run time is:" << endTime - startTime << "ms" << endl;*/
return 0;
}