1. 程式人生 > >【題解】 Luogu CF375D Tree and Queries

【題解】 Luogu CF375D Tree and Queries

原題傳送門

莫隊好題

我一上來想寫線段樹,隨後覺得不好寫並棄坑

我們可以看見沒有修改操作,欽定莫隊

但這是在樹上,所以不能直接用莫隊(廢話)

我們要樹鏈剖分,使得節點和節點的子樹能在一個區間裡(不會樹鏈剖分的出門左轉洛咕樹鏈剖分模板

剩下的就是最基礎的莫隊,但是前置和後置++,--要注意qaq,我以前寫莫隊經常因為++,--的問題出鍋qaq

剩下一些細節見程式

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
#define N 100005
using namespace std;
inline int read() //io優化
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[36];int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
struct edge{
    int to,next;
}e[N<<1];
int head[N],cnt;
struct query{
    int l,r,id,bl,k;
}q[N];
int n,m,blocksize;
int c[N];
int in[N],out[N],w[N];
inline void dfs(register int x,register int fa)
{
    in[x]=++cnt;
    w[cnt]=c[x];
    for (register int i=head[x];i;i=e[i].next)
    {
        int y=e[i].to;
        if (y==fa) 
            continue;
        dfs(y,x);
    }
    out[x]=cnt;
}
inline bool cmp(register query a,register query b)
{
    return a.bl==b.bl?a.r<b.r:a.bl<b.bl;
}
int ans[N],f[N],res[N]; //f[i]表示當前顏色為i的節點的個數,ans[i]表示當前出現次數大於等於i的顏色數量,res是最後的結果
bool inq[N];
inline void update(register int x)
{
    if(inq[x])
        --ans[f[w[x]]--];
    else
        ++ans[++f[w[x]]];
    inq[x]^=1;
}
int main()
{
    n=read(),m=read();
    for(register int i=1;i<=n;++i)
        c[i]=read();
    for(register int i=1;i<n;++i)
    {
        int x=read(),y=read(); //鏈式前向星建圖
        e[++cnt]=(edge){y,head[x]};
        head[x]=cnt;
        e[++cnt]=(edge){x,head[y]};
        head[y]=cnt;
    }
    cnt=0;
    dfs(1,1); //樹剖
    blocksize=sqrt(n); //莫隊塊的大小
    for(register int i=1;i<=m;++i)
    {
        int v=read(),k=read();
        q[i]=(query){in[v],out[v],i,(in[v]-1)/blocksize+1,k};
    }
    sort(q+1,q+1+m,cmp);
    int l=1,r=0;
    for(register int i=1;i<=m;++i)
    {
        int ll=q[i].l,rr=q[i].r;
        while(l<ll)
            update(l++);
        while(l>ll)
            update(--l);
        while(r>rr)
            update(r--);
        while(r<rr)
            update(++r);
        res[q[i].id]=ans[q[i].k];
    }
    for(register int i=1;i<=m;++i)
    {
        write(res[i]);
        printf("\n");
    }
    return 0;
 }