Description
给您一颗树,每个节点有个初始值。
现在支持以下两种操作:
1. C i x(0<=x<2^31) 表示将i节点的值改为x。
2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。
Input
第一行有两个整数N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分别表示节点个数和操作个数。
下面一行N个整数,表示初始时每个节点的初始值。
接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树)。
接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。
Output
对于每个Q输出单独一行表示所求的答案。
题解:这个做法,有点牵强吧.
感觉像是空间不够闲着蛋疼才会这么去做.
离线也不是很高级.
对每种颜色建立一个基于 DFS 序的树状数组,权值代表的是一个点出现该颜色的次数.
我们想要查询两点间出现该颜色的次数,只需提取出 DFS 序中对应两点间路径即可.
可是由于空间不够用,只能按照所有颜色分类,依次离线处理一遍.
写起来挺麻烦的......
#include<bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)
#define maxn 300000
using namespace std;
struct OPT
{
int type;
int a,b,c,tag;
OPT(int type=0,int a=0,int b=0,int c=0,int tag=0):type(type),a(a),b(b),c(c),tag(tag){}
}opt[maxn];
vector<OPT>G[maxn];
struct BIT
{
#define N 300000
int C[maxn];
int lowbit(int t)
{
return t & (-t);
}
void update(int x,int delta)
{
while(x<N)
{
C[x]+=delta;
x+=lowbit(x);
}
}
int query(int x)
{
int tmp=0;
while(x>0)
{
tmp+=C[x];
x-=lowbit(x);
}
return tmp;
}
}tree;
char str[10];
int n,Q,edges,tot,tim,mkk=0;
int col[maxn],Arr[maxn],hd[maxn],to[maxn<<1],nex[maxn<<1],dfn[maxn],ln[maxn],st[maxn],ed[maxn];
int siz[maxn],hson[maxn],dep[maxn],top[maxn],fa[maxn],answer[maxn];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void dfs1(int u,int ff)
{
ln[++tim]=u,dfn[u]=st[u]=tim,siz[u]=1,dep[u]=dep[ff]+1,fa[u]=ff;
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[hson[u]]) hson[u]=v;
}
ed[u]=tim;
}
void dfs2(int u,int tp)
{
top[u]=tp;
if(hson[u]) dfs2(hson[u],tp);
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==fa[u]||v==hson[u]) continue;
dfs2(v,v);
}
}
int LCA(int x,int y)
{
while(top[x]^top[y]) dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]];
return dep[x]<dep[y]?x:y;
}
void solve(int cur)
{
for(int i=0,sz=G[cur].size();i<sz;++i)
{
OPT cn=G[cur][i];
switch(cn.type)
{
case -1:
{
int u=cn.a;
tree.update(st[u], -1);
tree.update(ed[u]+1, +1);
break;
}
case 1 :
{
int u=cn.a;
tree.update(st[u], 1);
tree.update(ed[u]+1, -1);
break;
}
case 2 :
{
int u=cn.a;
int v=cn.b;
int c=cn.c;
int g=cn.tag;
int lca = LCA(u,v);
answer[g]=tree.query(dfn[u])+tree.query(dfn[v])-tree.query(dfn[lca])-tree.query(dfn[fa[lca]]);
break;
}
}
}
for(int i=0,sz=G[cur].size();i<sz;++i)
{
OPT cn=G[cur][i];
if(cn.type==-1) tree.update(st[cn.a], +1), tree.update(ed[cn.a]+1,-1);
if(cn.type==1) tree.update(st[cn.a], -1), tree.update(ed[cn.a]+1, +1);
}
}
int main()
{
// setIO("input");
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;++i) scanf("%d",&col[i]),Arr[++tot]=col[i];
for(int i=1;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y), add(y,x);
}
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=Q;++i)
{
scanf("%s",str);
switch(str[0])
{
case 'C' :
{
opt[i].type=1;
scanf("%d%d",&opt[i].a,&opt[i].b);
Arr[++tot]=opt[i].b;
break;
}
case 'Q' :
{
opt[i].type=2;
scanf("%d%d%d",&opt[i].a,&opt[i].b,&opt[i].c);
Arr[++tot]=opt[i].c;
break;
}
}
}
sort(Arr+1,Arr+1+tot);
for(int i=1;i<=Q;++i)
{
if(opt[i].type==1) opt[i].b=lower_bound(Arr+1,Arr+1+tot,opt[i].b)-Arr;
if(opt[i].type==2) opt[i].c=lower_bound(Arr+1,Arr+1+tot,opt[i].c)-Arr;
}
for(int i=1;i<=n;++i)
{
col[i]=lower_bound(Arr+1,Arr+1+tot,col[i])-Arr;
G[col[i]].push_back(OPT(1,i,0,0,0));
}
for(int i=1;i<=Q;++i)
{
if(opt[i].type==2)
{
OPT P=opt[i];
P.tag=++mkk;
G[opt[i].c].push_back(P);
}
else
{
int u=opt[i].a,v=opt[i].b;
G[col[u]].push_back(OPT(-1,u,0,0,0));
G[v].push_back(OPT(1,u,0,0,0));
col[u]=v;
}
}
for(int i=1;i<maxn;++i)
{
if(G[i].size()) solve(i);
}
for(int i=1;i<=mkk;++i)
{
printf("%d\n",answer[i]);
}
return 0;
}