「CF375D Tree and Queries」

题目

\(dsu\ on\ tree\)的板子题了

\(dsu\ on\ tree\)本质上一种优秀通过轻重链剖分优化到\(O(nlogn)\)的暴力

一般用来解决没有修改的允许离线的子树查询问题

首先先来处理出每一个节点的重儿子

接下来按照如下的顺序统计

  1. 递归处理当前节点的所有轻儿子

  2. 递归处理重儿子

  3. 遍历一遍整棵子树,统计信息(但是不用访问当前点的重儿子)

  4. 如果这个节点是重儿子,就返回,否则的话就清空所有信息

所以第三步,不用访问当前点的重儿子就是因为在第四步的时候重儿子没有被清空

至于这道题我们数颜色的时候开一个树状数组,每次存储颜色的桶数量发生变化,就在树状数组里修改相应的位置

查一个后缀和就好了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define re register
#define lowbit(x) ((x)&(-x))
#define maxn 100005
inline int read() {
    int x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,num,__,Son,tot;
struct Ask{int x,k,rk;}q[maxn];
struct E{int v,nxt;}e[maxn<<1];
int son[maxn],sum[maxn],deep[maxn],col[maxn];
int dfn[maxn],c[maxn],tax[maxn],Ans[maxn],head[maxn];
inline int cmp(Ask A,Ask B) {return dfn[A.x]<dfn[B.x];}
inline void C(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
inline void add(int x,int val) {for(re int i=x;i;i-=lowbit(i)) c[i]+=val;}
inline int ask(int x) {int now=0;for(re int i=x;i<=n;i+=lowbit(i)) now+=c[i];return now;}
void dfs1(int x) {
    sum[x]=1;int maxx=-1;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(deep[e[i].v]) continue;
        deep[e[i].v]=deep[x]+1,dfs1(e[i].v);
        sum[x]+=sum[e[i].v];
        if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v;
    }
}
void dfs2(int x) {
    for(re int i=head[x];i;i=e[i].nxt)
        if(deep[e[i].v]>deep[x]&&son[x]!=e[i].v) dfs2(e[i].v);
    if(son[x]) dfs2(son[x]);
    dfn[x]=++__;
}
void calc(int x,int opt) {
    if(tax[col[x]]) add(tax[col[x]],-1);
    tax[col[x]]+=opt;
    if(tax[col[x]]) add(tax[col[x]],1);
    for(re int i=head[x];i;i=e[i].nxt)
        if(deep[e[i].v]>deep[x]&&Son!=e[i].v) calc(e[i].v,opt);
}
void dfs(int x,int opt) {
    for(re int i=head[x];i;i=e[i].nxt) 
    if(deep[e[i].v]>deep[x]&&son[x]!=e[i].v) 
        dfs(e[i].v,0);
    if(son[x]) dfs(son[x],1);
    Son=son[x];calc(x,1);Son=0;
    while(q[tot].x==x) {
        Ans[q[tot].rk]=ask(q[tot].k);tot++;
    }
    if(!opt) calc(x,-1);
}
int main() {
    n=read(),m=read();
    for(re int i=1;i<=n;i++) col[i]=read();
    for(re int x,y,i=1;i<n;i++) x=read(),y=read(),C(x,y),C(y,x);
    deep[1]=1,dfs1(1),dfs2(1);
    for(re int i=1;i<=m;i++) q[i].rk=i,q[i].x=read(),q[i].k=read();
    std::sort(q+1,q+m+1,cmp);tot=1;dfs(1,1);
    for(re int i=1;i<=m;i++) printf("%d\n",Ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10473422.html