Codeforces 375D D. Tree and Queries

Posted lltyyc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 375D D. Tree and Queries相关的知识,希望对你有一定的参考价值。

传送门

题意:

给一棵树,每个节点有一个颜色,询问x为根的子树,出现次数大于等于k的颜色个数。

输入格式:

第一行 个数 n,m 表示节点数和询问数。

接下来一行 个数,第 个数 ci ?表示节点 的颜色。

接下来 n-1 行,每行两个数 a,b 表示一条边。

接下来 行,每行两个数 x,k 表示一组询问。

数据范围: $n.m,c,k \in [1,10^5]$

显然可以 $dsu\ on\ tree$

可以用权值树状数组直接维护当前每个出现次数大于等于 $k$ 的颜色数量

但是因为每次修改都只有加 $1$ 或减 $1$

所以可以直接维护 $ans[i]$ 表示出现次数大于等于 $i$ 的颜色数量

具体代码就可以这样维护:

//cnt是每种颜色当前出现次数
inline void ins(int c)  cnt[c]++; ans[cnt[c]]++; 
inline void del(int c)  ans[cnt[c]]--; cnt[c]--; 

其他就是 $dsu\ on\ tree$ 的基本操作了

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
inline int read()

    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9)  if(ch==-) f=-1; ch=getchar(); 
    while(ch>=0&&ch<=9)  x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); 
    return x*f;

const int N=2e6+7;
int fir[N],from[N<<1],to[N<<1],cntt;
inline void add(int &a,int &b)  from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; 
int n,m,col[N],Ans[N];
struct dat
    int x,k,id;//以节点x为根,出现次数大于等于k的询问,编号为id
    inline bool operator < (const dat &tmp) const 
        return x<tmp.x;
    
d[N];//存询问并准备把询问按x排序
int sz[N],son[N];
void dfs1(int x,int fa)

    sz[x]=1;
    for(int i=fir[x];i;i=from[i])
    
        int &v=to[i]; if(v==fa) continue;
        dfs1(v,x); sz[x]+=sz[v];
        if(sz[v]>sz[son[x]]) son[x]=v;
    

int id[N],dfs_clock,cnt[N],ans[N];//id是dfs序为i的节点编号
inline void ins(int c)  cnt[c]++; ans[cnt[c]]++; 
inline void del(int c)  ans[cnt[c]]--; cnt[c]--; 
inline void work(int x)//处理与节点x有关的询问

    for(int i=lower_bound(d+1,d+m+1,(dat)x,0,0)-d ; d[i].x==x ; i++)
        Ans[d[i].id]=ans[d[i].k];

void dfs2(int x,int fa,bool flag)//flag判断是否要清空子树

    id[++dfs_clock]=x; int L=dfs_clock;//L是轻儿子子树左区间
    if(!son[x])  ins(col[x]); work(x); if(!flag) del(col[x]); return; 
    //注意上面对于叶节点的特判中要先ins再work再del
    for(int i=fir[x];i;i=from[i])
    
        int &v=to[i]; if(v==fa||v==son[x]) continue;
        dfs2(v,x,0);
    
    int R=dfs_clock;//轻儿子子树右区间
    dfs2(son[x],x,1);
    for(int i=L;i<=R;i++) ins( col[id[i]] );
    work(x);
    if(!flag) for(int i=L;i<=dfs_clock;i++) del( col[id[i]] );//注意清除的区间不是[L,R]

int main()

    n=read(),m=read(); int a,b;
    for(int i=1;i<=n;i++) col[i]=read();
    for(int i=1;i<n;i++)
    
        a=read(),b=read();
        add(a,b); add(b,a);
    
    dfs1(1,0);
    for(int i=1;i<=m;i++) d[i].x=read(),d[i].k=read(),d[i].id=i;
    sort(d+1,d+m+1);//离散化
    dfs2(1,0,1);
    for(int i=1;i<=m;i++) printf("%d\n",Ans[i]);
    return 0;

 

以上是关于Codeforces 375D D. Tree and Queries的主要内容,如果未能解决你的问题,请参考以下文章

[Codeforces375D]Tree and Queries(莫队算法)

CodeForces 375D Tree and Queries 莫队||DFS序

Codeforces Round #475 (Div. 2) D. Destruction of a Tree

343D/Codeforces Round #200 (Div. 1) D. Water Tree dfs序+数据结构

Codeforces Round #353 (Div. 2) D. Tree Construction (二分,stl_set)

Codeforces Round #353 (Div. 2) D. Tree Construction (BST询问父亲节点)