hdu 4358 Boring counting dfs序+莫队+离散化

Boring counting

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 98304/98304 K (Java/Others)


Problem Description
In this problem we consider a rooted tree with N vertices. The vertices are numbered from 1 to N, and vertex 1 represents the root. There are integer weights on each vectice. Your task is to answer a list of queries, for each query, please tell us among all the vertices in the subtree rooted at vertice u, how many different kinds of weights appear exactly K times?
 

 

Input
The first line of the input contains an integer T( T<= 5 ), indicating the number of test cases.
For each test case, the first line contains two integers N and K, as described above. ( 1<= N <= 10 5, 1 <= K <= N )
Then come N integers in the second line, they are the weights of vertice 1 to N. ( 0 <= weight <= 10 9 )
For next N-1 lines, each line contains two vertices u and v, which is connected in the tree.
Next line is a integer Q, representing the number of queries. (1 <= Q <= 10 5)
For next Q lines, each with an integer u, as the root of the subtree described above.
 

 

Output
For each test case, output "Case #X:" first, X is the test number. Then output Q lines, each with a number -- the answer to each query.

Seperate each test case with an empty line.
 

 

Sample Input
1 3 1 1 2 2 1 2 1 3 3 2 1 3
 

 

Sample Output
Case #1: 1 1 1
 

 

Author
fish@UESTC_Oblivion
 

 

Source
题意:给你一棵树,n个节点,以1为根,每个节点有一个权值w;
   q个询问,每个询问问,以该点为根的子树下某个权值出现k次的个数;
思路:首先w很大,用map会超时;需要离散化一下;
   处理子树问题,利用dfs序,改成区间处理;
   区间处理权值出现k次的树,利用莫队得到答案;
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pi (4*atan(1.0))
#define eps 1e-14
const int N=1e5+10,M=1e6+10,inf=1e9+10;
const ll INF=1e18+10,mod=2147493647;
struct is
{
    int v,nex;
}edge[N<<1];
int head[N<<1],edg,in[N],out[N],tot,pos[N],w[N];
vector<int>l;
int a[N],flag[N];
void add(int u,int v)
{
    edg++;
    edge[edg].v=v;
    edge[edg].nex=head[u];
    head[u]=edg;
}
void dfs(int u,int fa)
{
    in[u]=++tot;
    for(int i=head[u];i!=-1;i=edge[i].nex)
    {
        int v=edge[i].v;
        if(v==fa)continue;
        dfs(v,u);
    }
    out[u]=tot;
}
struct hh
{
    int l,r,now;
    bool operator <(const hh b)
    {
        if(pos[l]!=pos[b.l])
            return pos[l]<pos[b.l];
        return r<b.r;
    }
}p[N];
int ans[N],mp[N],z[N];
void add(int pos)
{
    z[mp[a[pos]]]--;
    mp[a[pos]]++;
    z[mp[a[pos]]]++;
}
void del(int pos)
{
    z[mp[a[pos]]]--;
    mp[a[pos]]--;
    z[mp[a[pos]]]++;
}
void init(int n)
{
    l.clear();
    memset(mp,0,sizeof(mp));
    memset(z,0,sizeof(z));
    int s=(int)(sqrt(n));
    for(int i=1;i<=n;i++)
        pos[i]=(i-1)/s+1;
    memset(head,-1,sizeof(head));
    memset(a,0,sizeof(a));
    edg=0;
    tot=0;
}
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        if(cas!=1)
            printf("\n");
        int n,k;
        scanf("%d%d",&n,&k);
        init(n);
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]),l.push_back(w[i]);
        sort(l.begin(),l.end());
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs(1,-1);
        for(int i=1;i<=n;i++)
            flag[in[i]]=i;
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(l.begin(),l.end(),w[flag[i]])-l.begin();
        int q;
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            int x;
            scanf("%d",&x);
            p[i].l=in[x];
            p[i].r=out[x];
            p[i].now=i;
        }
        sort(p+1,p+1+q);
        int L=1,R=0;
        for(int i=1;i<=q;i++)
        {
            //cout<<p[i].l<<" "<<p[i].r<<" "<<p[i].now<<endl;
            while(L<p[i].l)
            {
                del(L);
                L++;
            }
            while(L>p[i].l)
            {
                L--;
                add(L);
            }
            while(R>p[i].r)
            {
                del(R);
                R--;
            }
            while(R<p[i].r)
            {
                R++;
                add(R);
            }
            ans[p[i].now]=z[k];
        }
        printf("Case #%d:\n",cas++);
        for(int i=1;i<=q;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/jhz033/p/6145276.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值