树上莫队
题目大意:给你一棵树,每个节点有一个颜色,每次询问从
u
u
到出现第
k
k
多的颜色。
数据范围:
这道题是LOJ6273的树上版。
对于每一种颜色,定义一个二元组 c,x c , x 表示颜色 c c 出现了次,用vector存储,把它放到序列上并分块。记一个 f[] f [ ] 表示这种情况是否出现,每次修改颜色的时候把 a[c][x] a [ c ] [ x ] 去掉,把 a[c][x+1] a [ c ] [ x + 1 ] 或 a[c][x−1] a [ c ] [ x − 1 ] 加上。处理询问的时候做一个类似前缀和的东西就好了。
具体实现见代码:
#include<cmath>
#include<vector>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50005
#define F inline
#define V F void
using namespace std;
struct edge{ int next,to; }ed[N<<1];
struct query{ int x,y,id,t; }q[N];
struct node{ int x,s; }nd[N];
int n,k,Q,tp,B,d,LG,c[N],t[N],cc[N],p[N],ans[N],ti[N];
int h[N],fa[N][20],dep[N],stk[N],num[N],sum[N],id[N];
bool f[N],f1[N]; vector <int> a[N];
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; return *l++;
}
F int _read(){
int x=0; char ch=readc();
while (!isdigit(ch)) ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
V writec(int x){ if (x>9) writec(x/10); putchar(x%10+48); }
V _write(int x){ writec(x),putchar('\n'); }
V addedge(int x,int y){ ed[++k]=(edge){h[x],y},h[x]=k; }
F bool cmp1(node a,node b){ return a.s==b.s?a.x>b.x:a.s>b.s; }
F bool cmp2(query a,query b){ return num[a.x]==num[b.x]?num[a.y]<num[b.y]:num[a.x]<num[b.x]; }
F int LCA(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int j=LG;~j;j--)
if (dep[fa[x][j]]>=dep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=LG;~j;j--)
if (fa[x][j]!=fa[y][j])
x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
void dfs(int x){
ti[x]=++ti[0]; int now=tp;
for (int i=h[x],v;i;i=ed[i].next)
if ((v=ed[i].to)!=fa[x][0]){
dep[v]=dep[x]+1,fa[v][0]=x,dfs(v);
if (tp-now>=B) for (d++;tp!=now;) num[stk[tp--]]=d;
}
stk[++tp]=x;
}
V nsrt(int x,int w){
int l=a[x][sum[x]],r=a[x][sum[x]+=w];
if (l) f1[l]=false,t[(l-1)/B+1]--;
if (r) f1[r]=true,t[(r-1)/B+1]++;
}
V rvrs(int x){ nsrt(p[x],((f[x]^=1)<<1)-1); }
V mdfy(int x,int y){
while (x!=y)
if (dep[x]>dep[y]) rvrs(x),x=fa[x][0];
else rvrs(y),y=fa[y][0];
}
F int srch(int x){
int now=1;
while (x>t[now]) x-=t[now++];
for (int i=(now-1)*B+1;i<=now*B;i++)
if (!(x-=f1[i])) return i;
}
int main(){
n=_read(),Q=_read(),LG=log2(n),B=sqrt(n);
for (int i=1;i<=n;i++) c[i]=cc[i]=_read();
for (int i=1,x,y;i<n;i++)
x=_read(),y=_read(),addedge(x,y),addedge(y,x);
sort(cc+1,cc+n+1); int s=unique(cc+1,cc+n+1)-(cc+1);
for (int i=1;i<=n;i++){
c[i]=lower_bound(cc+1,cc+s+1,c[i])-cc;
p[i]=nd[i].x=c[i],nd[i].s=++sum[c[i]];
}
sort(nd+1,nd+n+1,cmp1),dep[1]=1,dfs(1);
for (int i=1;i<=s;i++) a[i].push_back(0);
for (int i=n;i;i--)
a[nd[i].x].push_back(i),id[i]=nd[i].x;
for (int j=1;j<=LG;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
memset(sum,0,sizeof(sum));
for (int i=1,x,y,k;i<=Q;i++){
x=_read(),y=_read(),k=_read();
if (ti[x]>ti[y]) swap(x,y);
q[i]=(query){x,y,i,k};
}
sort(q+1,q+Q+1,cmp2);
for (int i=1,x,y,l;i<=Q;i++){
x=q[i].x,y=q[i].y,l=LCA(x,y);
if (i==1) mdfy(x,y);
else mdfy(q[i-1].x,x),mdfy(q[i-1].y,y);
rvrs(l),ans[q[i].id]=id[srch(q[i].t)],rvrs(l);
}
for (int i=1;i<=Q;i++) _write(cc[ans[i]]);
return 0;
}