Description
给定一棵N 个节点的树,标号从1~N。每个点有一个权值。要求维护两种操作:
1. C i x(0<=x<2^31) 表示将i 点权值变为x
2. Q i j x(0<=x<2^31) 表示询问i 到j 的路径上有多少个值为x 的节点
Solution
这是一道很裸的树链剖分的题目,有一道题很这题极其类似【SDOI2014】旅行 不过多了一些操作而已。
用动态开空间的方法
这种方法又快又好大,没有什么麻烦的操作,全是些基础。
要打个离散化加hash
我是一个c++选手,一个map就搞定了。
注意
root有可能会爆掉,这个坑了我10分,TAT
在线大法好!
Code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100007;
int i,j,k,l,n,m,ans;
int first[maxn*2],next[maxn*2],last[maxn*2],num,tot;
int size[maxn],fa[maxn],deep[maxn],son[maxn],w[maxn],sum;
int root[maxn*6],top[maxn],tt,e[maxn],ppo,b[maxn];
bool bz[maxn];
map<int,int> f;
char s[5];
struct nod{
int a,b,c;
}a[maxn];
struct node{
int l,r,sum;
}t[maxn*200];
void add(int x,int y){
last[++num]=y;
next[num]=first[x];
first[x]=num;
last[++num]=x;
next[num]=first[y];
first[y]=num;
}
void dfs1(int x,int y){
int i,k=0;
size[x]=1;
for(i=first[x];i;i=next[i]){
if(last[i]!=y){
fa[last[i]]=x;
deep[last[i]]=deep[x]+1;
dfs1(last[i],x);
size[x]+=size[last[i]];
if(k<size[last[i]]){
k=size[last[i]];
son[x]=last[i];
}
}
}
}
void dfs2(int x,int y){
top[x]=y;
w[x]=++tot;
if(!son[x]) return;
dfs2(son[x],y);
for(int i=first[x];i;i=next[i]){
if(last[i]!=fa[x]&&last[i]!=son[x]){
dfs2(last[i],last[i]);
}
}
}
void change(int &x,int l,int r,int y,int z){
if(x==0)x=++sum;
if(l==r){t[x].sum=z;return;}
int mid=(l+r)/2;
if(y<=mid)change(t[x].l,l,mid,y,z);
else change(t[x].r,mid+1,r,y,z);
t[x].sum=t[t[x].l].sum+t[t[x].r].sum;
}
int findsum(int x,int l,int r,int y,int z){
if(x==0)return 0;
if(y>z)return 0;
if(l==y&&r==z){
return t[x].sum;
}
else{
int mid=(l+r)/2;
if(z<=mid)return findsum(t[x].l,l,mid,y,z);
else if(y>mid)return findsum(t[x].r,mid+1,r,y,z);
else{
return findsum(t[x].l,l,mid,y,mid)+findsum(t[x].r,mid+1,r,mid+1,z);
}
}
}
int zhaosum(int x,int y,int z){
int f1=top[x],f2=top[y],o=0;
while(f1!=f2){
if(deep[f1]<deep[f2]){
swap(f1,f2);
swap(x,y);
}
o+=findsum(root[z],1,n,w[f1],w[x]);
x=fa[f1];f1=top[x];
}
if(deep[x]<deep[y])swap(x,y);
return o+=findsum(root[z],1,n,w[y],w[x]);
}
bool cmp(nod x,nod y){
return x.b<y.b;
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n){
scanf("%d",&b[i]);
if(!f[b[i]]){
f[b[i]]=++ppo;
}
b[i]=f[b[i]];
}
fo(i,1,n-1){
scanf("%d%d",&k,&l);
add(k,l);
}
deep[1]=1;
dfs1(1,0);
dfs2(1,1);
fo(i,1,n){
change(root[b[i]],1,n,w[i],1);
}
fo(i,1,m){
scanf("%s",s+1);
if(s[1]=='C'){
scanf("%d%d",&k,&l);
change(root[b[k]],1,n,w[k],0);
if(!f[l])f[l]=++ppo;
b[k]=f[l];
change(root[b[k]],1,n,w[k],1);
}
else{
scanf("%d%d%d",&k,&l,&tt);
if(!f[tt]){
printf("0\n");
continue;
}
ans=zhaosum(k,l,f[tt]);
printf("%d\n",ans);
}
}
}