hdu 4358 Boring counting 线段树离线操作

来源:互联网 发布:vscode代码提示快捷键 编辑:程序博客网 时间:2024/05/17 09:13

题目大意:给一棵树,1为根。每个节点都有一个权值。Q次询问,每个询问为,以x为根的子树中,刚好出现了k次的权有几种。

关键是要把树形结构边为线性结构,我们这里使用欧拉序列,问题变为了一个区间,刚好出现了k次的数字有几个。

这个问题则是很经典的离线问题了,线段树点i的值表示区间[i,j]中,刚好出现了k次的数字的个数(j具有动态意义)。我们用id[x][j]表示,数字x在整个数列中第j次出现的位置。每次维护的时候就是区间 idx[x][j-k]+1 到 id[x][j-k+1] 全部+1,区间 id[x][j-k-1]+1 到  id[x][j-k] 全部-1。


#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<cmath>#include<cctype>#include<string>#include<algorithm>#include<iostream>#include<ctime>#include<map>#include<set>using namespace std;#define MP(x,y) make_pair((x),(y))#define PB(x) push_back(x)typedef __int64 LL;//typedef unsigned __int64 ULL;/* ****************** */const int INF=1000111222;const double INFF=1e200;const double eps=1e-8;const int mod=1000000007;const int NN=100010;const int MM=10010;/* ****************** */const int MOD=233341;int hash[MOD];vector<int>id[MOD];int a[NN],b[NN],ll[NN],rr[NN],tsp;struct G{    int v,next;}E[NN*2];int p[NN],T;struct Q{    int l,r,id,ans;    bool operator<(const Q& tt)const    {        return r<tt.r;    }}line[NN];int lazy[NN*4];void add(int u,int v){    E[T].v=v;    E[T].next=p[u];    p[u]=T++;}int get_hash(int x){    int key=x%MOD;    for(;;key++)    {        if(key==MOD)            key=0;        if(hash[key]==-1 || hash[key]==x)        {            hash[key]=x;            return key;        }    }    return -1;}void dfs(int u,int fa){    ll[u]=++tsp;    int i,v;    for(i=p[u];i+1;i=E[i].next)    {        v=E[i].v;        if(v==fa)            continue;        dfs(v,u);    }    rr[u]=tsp;}void push_down(int R){    if(lazy[R]!=0)    {        lazy[R<<1]+=lazy[R];        lazy[R<<1|1]+=lazy[R];        lazy[R]=0;    }}int  get_mid(int l,int r){    return (l+r)>>1;}void update(int l,int r,int R,int st,int en,int ad){    if(l<=st && en<=r)    {        lazy[R]+=ad;        return;    }    push_down(R);    int mid=get_mid(st,en);    if(l<=mid)        update(l,r,R<<1,st,mid,ad);    if(r>mid)        update(l,r,R<<1|1,mid+1,en,ad);}int query(int x,int R,int st,int en){    if(st==en)        return lazy[R];    push_down(R);    int mid=get_mid(st,en);    if(x<=mid)        return query(x,R<<1,st,mid);    return query(x,R<<1|1,mid+1,en);}bool cmp(Q x,Q y){    return x.id<y.id;}void solve(int n,int q,int k){    memset(lazy,0,sizeof(lazy));    int i,x,ge,j=1;    for(i=1;i<=n;i++)    {        x=a[i];        id[x].push_back(i);        ge=id[x].size()-1;        if(ge>=k)        {            update(id[x][ge-k]+1,id[x][ge-k+1],1,1,n,1);            if(ge-k>0)            {                update(id[x][ge-k-1]+1,id[x][ge-k],1,1,n,-1);            }        }        while(j<=q && line[j].r==i)        {            line[j].ans=query(line[j].l,1,1,n);            j++;        }    }    sort(line+1,line+1+q,cmp);    for(i=1;i<=q;i++)    {        printf("%d\n",line[i].ans);    }}int main(){    int cas,ee=0;    int n,k;    int i,x,y,q;    scanf("%d",&cas);    while(cas--)    {        memset(hash,-1,sizeof(hash));        memset(p,-1,sizeof(p));        T=0;        tsp=0;        for(i=0;i<MOD;i++)        {            id[i].clear();            id[i].push_back(0);        }        scanf("%d%d",&n,&k);        for(i=0;i<n;i++)        {            scanf("%d",&a[i]);            b[i+1]=get_hash(a[i]);        }    //    for(i=1;i<=n;i++)    //        printf("%d%c",b[i],i==n?'\n':' ');        for(i=1;i<n;i++)        {            scanf("%d%d",&x,&y);            add(x,y);            add(y,x);        }        dfs(1,-1);        for(i=1;i<=n;i++)        {            a[ll[i]]=b[i];        }/*        for(i=1;i<=n;i++)        {            printf("%d %d\n",ll[i],rr[i]);            printf("w==%d\n",a[i]);        }*/        scanf("%d",&q);        for(i=1;i<=q;i++)        {            scanf("%d",&x);            line[i].l=ll[x];            line[i].r=rr[x];            line[i].id=i;        }        sort(line+1,line+1+q);        printf("Case #%d:\n",++ee);        solve(n,q,k);        if(cas)            puts("");    }    return 0;}


0 0