题目描述
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,并记下了途中留宿过的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
输入格式
输入的第一行包含整数N,Q依次表示城市数和事件数。
接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的评级和信仰。 接下来N-1行每行两个整数x,y表示一条双向道路。
接下来Q行,每行一个操作,格式如上所述。
输出格式
对每个QS和QM事件,输出一行,表示旅行者记下的数字。
输入输出样例
输入
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
输出
8
9
11
3
这题一眼过去你会发现其实跟树剖板子没啥区别,就是多了个约束宗教信仰,我们很自然的能想到对每个宗教都开个线段树来做,但因为会爆空间,所以要动态开点,完美的把空间降到了
O
(
n
l
o
g
)
O(nlog)
O(nlog)级别,其余就按板子打就是了。
code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,q,x,y,w[N],c[N],tot,first[N],Next[N*2],to[N*2];
int mson[N],zx[N],id[N],index_,dep[N],f[N],siz[N];
int ls[N*40],rs[N*40],val1[N*40],val2[N*40],cnt,rt[N];
string saber;
int Read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return f*x;
}
void add(int a,int b)
{
tot++;
Next[tot]=first[a];
first[a]=tot;
to[tot]=b;
}
void dfs1(int u,int fa)
{
int Max=0;
for(int i=first[u];i;i=Next[i])
{
int v=to[i];
if(v==fa) continue;
dep[v]=dep[u]+1;
f[v]=u;
dfs1(v,u);
siz[u]+=siz[v];
if(Max<siz[v]) Max=siz[v],mson[u]=v;
}
}
void dfs2(int u,int zz)
{
id[u]=++index_;
zx[u]=zz;
if(mson[u]) dfs2(mson[u],zz);
for(int i=first[u];i;i=Next[i])
{
int v=to[i];
if(v==f[u]||v==mson[u]) continue;
dfs2(v,v);
}
}
void pushup(int u)
{
val1[u]=max(val1[ls[u]],val1[rs[u]]);
val2[u]=val2[ls[u]]+val2[rs[u]];
}
void update(int &u,int l,int r,int pos,int val)
{
if(!u) u=++cnt;
if(l==r)
{
val1[u]=val2[u]=val;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) update(ls[u],l,mid,pos,val);
else update(rs[u],mid+1,r,pos,val);
pushup(u);
}
void Delete(int u,int l,int r,int pos)
{
if(l==r)
{
val1[u]=val2[u]=0;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) Delete(ls[u],l,mid,pos);
else Delete(rs[u],mid+1,r,pos);
pushup(u);
}
int query1(int u,int l,int r,int op,int ed)
{
if(l>=op&&r<=ed) return val1[u];
int Max=0;
int mid=(l+r)>>1;
if(op<=mid) Max=max(Max,query1(ls[u],l,mid,op,ed));
if(ed>mid) Max=max(Max,query1(rs[u],mid+1,r,op,ed));
return Max;
}
int query2(int u,int l,int r,int op,int ed)
{
if(l>=op&&r<=ed) return val2[u];
int sum=0;
int mid=(l+r)>>1;
if(op<=mid) sum+=query2(ls[u],l,mid,op,ed);
if(ed>mid) sum+=query2(rs[u],mid+1,r,op,ed);
return sum;
}
int Query1(int u,int v,int col)
{
int Max=0;
while(zx[u]!=zx[v])
{
if(dep[zx[u]]<dep[zx[v]]) swap(u,v);
Max=max(Max,query1(rt[col],1,n,id[zx[u]],id[u]));
u=f[zx[u]];
}
if(dep[u]>dep[v]) swap(u,v);
Max=max(Max,query1(rt[col],1,n,id[u],id[v]));
return Max;
}
int Query2(int u,int v,int col)
{
int sum=0;
while(zx[u]!=zx[v])
{
if(dep[zx[u]]<dep[zx[v]]) swap(u,v);
sum+=query2(rt[col],1,n,id[zx[u]],id[u]);
u=f[zx[u]];
}
if(dep[u]>dep[v]) swap(u,v);
sum+=query2(rt[col],1,n,id[u],id[v]);
return sum;
}
int main()
{
n=Read(),q=Read();
for(int i=1;i<=n;i++) w[i]=Read(),c[i]=Read(),siz[i]=1;
for(int i=1;i<n;i++){
x=Read(),y=Read();
add(x,y),add(y,x);
}
dfs1(1,0),dfs2(1,1);
for(int i=1;i<=n;i++) update(rt[c[i]],1,n,id[i],w[i]);
for(int i=1;i<=q;i++)
{
cin>>saber,x=Read(),y=Read();
// cout<<saber<<" "<<x<<" "<<y<<endl;
if(saber=="CC")
Delete(rt[c[x]],1,n,id[x]),update(rt[y],1,n,id[x],w[x]),c[x]=y;
if(saber=="CW")
Delete(rt[c[x]],1,n,id[x]),update(rt[c[x]],1,n,id[x],y),w[x]=y;
if(saber=="QS")
printf("%d\n",Query2(x,y,c[x]));
if(saber=="QM")
printf("%d\n",Query1(x,y,c[x]));
}
return 0;
}