BZOJ 4999: This Problem Is Too Simple! DFS序 + LCA + 树状数组 + 离线
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; }