hdu 4358

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4358

题解:先将树形结构转化成线性结构,这样问题就可以转化为求一个区间内,恰好出现K次的权值有多少种。利用树状数组记录K次的种数.

View Code
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#define lowbit(x) (x)&(-x)
using namespace std;
const int maxn = 100005;
struct nd{int next,v;}edge[maxn*2];
int head[maxn*2],sl[maxn][2],vis[maxn*2],sum[maxn*2],last[maxn*2],val[maxn*2],as[maxn*2],in[maxn*2];
int ecnt,idx,n,K;
vector<int>path[maxn];
void add(int u,int v)
{
    edge[ecnt].v = v;
    edge[ecnt].next = head[u];
    head[u] = ecnt++;
}
void update(int x,int v){if(x)for(;x<=idx;x+=lowbit(x))sum[x]+=v;}
int getsum(int x,int v){for(;x;x-=lowbit(x))v+=sum[x];return v;}
int bitser(int x)
{
    int l = 1,r = n,m;
    while(l < r){
        m = (l + r) >> 1;
        if(as[m]>=x)r = m;
        else l = m + 1;
    }return l;
}
void getlist(int x)
{
    sl[x][0] = ++idx;
    vis[idx] = x;
    for(int i = head[x]; ~i; i = edge[i].next)
    getlist(edge[i].v);
    sl[x][1] = ++idx;
    vis[idx] = -x;
}
void readin()
{
    int i,u,v;
    scanf("%d %d",&n,&K);
    for(i = 1; i <= n; ++ i)
    {scanf("%d",as+i);val[i] = as[i];}
    sort(as+1,as+n+1);
    for(i = 1; i <= n; ++ i)
    val[i] = bitser(val[i]);

    memset(head,-1,sizeof(head));
    memset(in,0,sizeof(in));
    ecnt = 0;
    for(i = 1; i < n; ++ i){
        scanf("%d %d",&u,&v);
        add(u,v); in[v]++;
    }
    idx = 0;
    getlist(1);
}
void processing()
{
    int i,k,v;
    memset(in,0,sizeof(in));
    memset(sum,0,sizeof(sum));
    memset(last,0,sizeof(last));
    for(i = 1; i <= n; ++ i){
        path[i].clear();
        path[i].push_back(0);
    }
    for(i = 1; i <= idx; ++ i)if(vis[i]>0){
        k = vis[i];
        v = val[k];
        path[v].push_back(i);
        in[v]++;
        if(in[v]>=K){
            if(in[v] > K){
                update(path[v][in[v]-K-1]+1,-1);
                update(path[v][in[v]-K]+1,1);
            }
            update(path[v][in[v]-K]+1,1);
            update(path[v][in[v]-K+1]+1,-1);
        }
    }else{
        k = -vis[i];
        as[k] = getsum(sl[k][0],0);
    }
}
void query()
{
    int m,k;
    scanf("%d",&m);
    while(m--){
        scanf("%d",&k);
        printf("%d\n",as[k]);
    }
}
int main()
{
    int T,cas=0;
    for(scanf("%d",&T);T--;){
        if(cas)puts("");
        printf("Case #%d:\n",++cas);
        readin();
        processing();
        query();
    }
    return 0;
}

posted on 2012-08-14 20:03  aigoruan  阅读(216)  评论(0)    收藏  举报

导航