【bzoj4999】This Problem Is Too Simple!
题意
给你一颗树,每个节点有个初始值 Wi
现在支持以下两种操作:
1. Cix,0≤x<231) 表示将 Wi 改为 x
2.Qijx,0≤x<231 表示询问i节点到j节点的路径上有多少个 W 为x的节点
解法
树链剖分:
本题的关键在于2操作,只要解决了2操作,就能够想出对应的1操作的方法
点的数目是105 ,操作的次数有 5∗105 ,所以不同的权值最多有 6∗105 个,可以考虑进行线段树动态加点,对于每一个权值构建一颗线段树。为了方便的表示权值,可以使用 map 给每一个权值一个编号
对于每一次1操作,首先在原本的 Wi 的线段树进行单点修改:在 dfni 处减1,然后在之后的 x 的线段树上进行单点修改:在dfni 处+1(当然,一开始给的 Wi,i∈【1,n】 要先加进去)
对于2操作,那只需要套用树链剖分路径查询的板子即可,只不过是在 x 的线段树上进行查询
复杂度
O(
nlog2n )
代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#define ls lson[k],l,mid
#define rs rson[k],mid+1,r
#define Rint register int
#define Lint long long int
using namespace std;
const int MAXN=1000010;
struct node
{
int next,to;
}t[MAXN];
int head[MAXN],num;
int lson[MAXN*4],rson[MAXN*4];
int dep[MAXN],rt[MAXN*2];
int siz[MAXN],son[MAXN];
int top[MAXN],dfn[MAXN];
int w[MAXN],f[MAXN];
int sum[MAXN*4];
int n,q,cnt,L;
int _cnt,tot;
int ans;
map<int,int> id;
void add(int u,int v)
{
t[++num]=(node){ head[u],v };
head[u]=num;
}
void Tarjan(int k)
{
siz[k]=1;
for(int i=head[k],x; i ;i=t[i].next)
{
x=t[i].to;
if( x==f[k] ) continue ;
dep[x]=dep[k]+1,f[x]=k;
Tarjan( x );
siz[k]+=siz[x];
if( siz[x]>siz[son[k]] || !son[k] ) son[k]=x;
}
}
void dfs(int k)
{
dfn[k]=++cnt;
if( son[k] ) top[son[k]]=top[k],dfs( son[k] );
for(int i=head[k],x; i ;i=t[i].next)
{
x=t[i].to;
if( x==f[k] || x==son[k] ) continue ;
top[x]=x,dfs( x );
}
}
void update(int &k,int l,int r,int x,int w)
{
if( !k ) k=++tot;
sum[k]+=w;
if( l==r ) return ;
int mid=(l+r)/2;
if( x<=mid ) update( ls,x,w );
else update( rs,x,w );
}
int query(int k,int l,int r,int L,int R)
{
if( !k ) return 0;
if( l==L && r==R ) return sum[k];
int mid=(l+r)/2;
if( R<=mid ) return query( ls,L,R );
else
if( L>mid ) return query( rs,L,R );
else return query( ls,L,mid )+query( rs,mid+1,R );
}
int work(int u,int v,int id)
{
int ret=0;
if( dep[u]<dep[v] ) swap( u,v );
while( top[u]!=top[v] )
{
if( dep[top[u]]<dep[top[v]] ) swap( u,v );
ret+=query( id,1,n,dfn[top[u]],dfn[u] );
u=f[top[u]];
}
if( dep[u]>dep[v] ) swap( u,v );
ret+=query( id,1,n,dfn[u],dfn[v] );
return ret;
}
int main()
{
int u,v,x;
char opt[5];
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
add( u,v ),add( v,u );
}
f[1]=dep[1]=1,Tarjan( 1 );
top[1]=1,dfs( 1 );
for(int i=1;i<=n;i++)
{
if( !id[w[i]] ) id[w[i]]=++_cnt;
update( rt[id[w[i]]],1,n,dfn[i],1 );
}
while( q-- )
{
scanf("%s",opt);
if( opt[0]=='C' )
{
scanf("%d%d",&u,&x);
update( rt[id[w[u]]],1,n,dfn[u],-1 );
if( !id[x] ) id[x]=++_cnt;
update( rt[id[x]],1,n,dfn[u],1 );
w[u]=x;
}
else
{
scanf("%d%d%d",&u,&v,&x);
if( !id[x] ) ans=0;
else ans=work( u,v,rt[id[x]] );
printf("%d\n",ans);
}
}
return 0;
}