Codeforces 375D Tree and Queries

Codeforces 375D Tree and Queries

数据结构,dsu on tree

题意

给一棵树,每个节点有颜色,给一些查询(k,v),问k及其子树中,出现大于等于v次的颜色有多少种。

思路

dsu on tree。复杂度 O(nlog2n) ,dsu的nlogn加上树状数组的logn。

dsu的过程中用树状数组维护出现t次的颜色的种数。dfs完一个节点处理他的所有询问。

代码

#include<bits\stdc++.h>
#define M(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN=100007;
const int
typedef long long LL;
struct Edge
{
    int to, ne;
}e[MAXN<<1];
int head[MAXN], edgenum;
int val[MAXN];
struct Query
{
    int k, ne;int id;
}qn[MAXN];
int qhead[MAXN], qam;
int sz[MAXN], hson[MAXN];
int C[MAXN];
inline int lowbit(int i) { return i&(-i); }
void change(int pos, int val)
{
    for(int i=pos;i<MAXN;i+=lowbit(i))
        C[i]+=val;
}
int query(int pos)
{
    int ans=0;
    for(int i=pos;i>=1;i-=lowbit(i))
        ans+=C[i];
    return ans;
}
void findson(int u, int fa)
{
    sz[u]=1;
    for(int i=head[u];~i;i=e[i].ne)
    {
        int to=e[i].to;
        if(to!=fa)
        {
            findson(to, u);
            if(!hson) hson[u]=to;
            else if(sz[hson[u]]<sz[to]) hson[u]=to;
            sz[u]+=sz[to];
        }
    }
}
int cnt[MAXN], hs;
void suan(int u, int fa, int v)
{
    if(cnt[val[u]]) change(cnt[val[u]], -1);
    cnt[val[u]]+=v;
    if(cnt[val[u]]) change(cnt[val[u]], 1);
    for(int i=head[u];~i;i=e[i].ne)
        if(e[i].to!=fa&&e[i].to!=hs)
            suan(e[i].to, u, v);
}
int res[MAXN];
void dfs(int u, int fa, int kp)
{
    for(int i=head[u];~i;i=e[i].ne)
    {
        int to=e[i].to;
        if(to!=fa&&to!=hson[u])
            dfs(to, u, 0);
    }
    if(hson[u]) dfs(hson[u], u, 1), hs=hson[u];
    suan(u, fa, 1);hs=0;
    for(int i=qhead[u];~i;i=qn[i].ne)
    {
        int x=query(MAXN-1);
        int y=query(qn[i].k-1);
        res[qn[i].id]=x-y;
    }
    if(!kp) suan(u, fa, -1);
}
int main()
{
    int n;
    while(scanf("%d", &n)==1)
    {
        int q;scanf("%d", &q);
        for(int i=1;i<=n;i++) scanf("%d", &val[i]);
        M(head, -1), M(qhead, -1);edgenum=qam=0;
        for(int i=1;i<n;i++)
        {
            int p, q;scanf("%d%d", &p, &q);
            e[edgenum].to=q, e[edgenum].ne=head[p], head[p]=edgenum++;
            e[edgenum].to=p, e[edgenum].ne=head[q], head[q]=edgenum++;
        }
        for(int i=1;i<=q;i++)
        {
            int t1, t2;scanf("%d%d", &t1, &t2);
            qn[qam].k=t2, qn[qam].ne=qhead[t1], qn[qam].id=i, qhead[t1]=qam++;
        }
        findson(1, -1);
        dfs(1, 0, 0);
        for(int i=1;i<=q;i++)
            printf("%d\n", res[i]);
    }
    //system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值