[HDU4358]Boring counting[线段树]

传送门
题意:
给你一棵树 树上的每个点有一个权值
先求出这棵树的dfs序 然后有一些询问 问你在询问的区间里面有多少的数恰好出现 k

题解:
我们可以这么做
就是把值都存在左端点上 离线地求值 (预先将询问按照右端点排个序
枚举右端点 看到当前右端点上的数是否超过了 k 次(要记录每个数出现的位置的
在线段树上区间修改单点查询(树状数组也是可以的2333
再看一下图理解一下
这里写图片描述
(灵魂画手。。。光速逃。。。

吐槽:
敲了九十几行代码的我 (头已经开始晕啦。。。
写完了之后(心情忐忑地跑样例 (当然是没跑过
然后收复了一下心情
开始gdb调试
(最后发现自己建树的函数都没调用!。。。。(是智障本人没错了。。。
然后跑系统测试(PE了好几发(以后题目要好好看啊!
代码不长不长。。。。(用ymz大佬的话来说“这不是几行就写完了?”
(雾

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
struct data{
    int l,r,sum;
}tree[N<<2];
struct node{
    int next,to;
}a[N<<1];
struct Yee{
    int rk,u,l,r;
}e[N];
int q[N],w[N],ed[N],st[N],yy[N],head[N],num[N],ans1=0,cnt=0;
vector<int> qx[N];

void add(int x,int y){
    a[++cnt].to=y,a[cnt].next=head[x],head[x]=cnt;
    a[++cnt].to=x,a[cnt].next=head[y],head[y]=cnt;
}

void dfs(int u,int fa){
    cnt++;st[u]=cnt;num[cnt]=w[u];
    for(int i=head[u];i!=-1;i=a[i].next){
        if(a[i].to!=fa) dfs(a[i].to,u);   
    }
    ed[u]=cnt;
}

void build(int index,int left,int right){
    tree[index].sum=0;
    tree[index].l=left,tree[index].r=right;
    int mid=(left+right)>>1;
    if(left==right) return ;
    build(index*2,left,mid);
    build(index*2+1,mid+1,right);
}

void change(int index,int left,int right,int d){
    if(left>right) return ;
    if(tree[index].l>=left&&tree[index].r<=right) { tree[index].sum+=d; return ; }
    if(tree[index*2].r>=left) change(index*2,left,right,d);
    if(tree[index*2+1].l<=right) change(index*2+1,left,right,d);
}

void search(int index,int x){
    ans1+=tree[index].sum;
    if(tree[index].l==tree[index].r) return ;
    if(x<=tree[index*2].r) search(index*2,x);
    if(x>=tree[index*2+1].l) search(index*2+1,x);
}

bool comp(Yee xx,Yee yy){ return xx.r<yy.r; }

int main(){
    int T;scanf("%d",&T);
    for(int cse=1;cse<=T;++cse){
        memset(head,-1,sizeof(head));
        printf("Case #%d:\n",cse);
        int n,k;scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i) scanf("%d",&q[i]),w[i]=q[i],qx[i].clear();
        sort(q+1,q+1+n);
        int ans=unique(q+1,q+1+n)-q-1;
        for(int i=1;i<=n;++i) w[i]=lower_bound(q+1,q+1+ans,w[i])-q;
        int x,y;cnt=0;
        for(int i=1;i<n;++i){
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        cnt=0,dfs(1,0);
        // for(int i=1;i<=n;++i) printf("num[%d]=%d\n",i,num[i]);
        int Q;scanf("%d",&Q);
        for(int i=1;i<=Q;++i){
            scanf("%d",&x);
            e[i].rk=i;e[i].u=x;
            e[i].l=st[x];e[i].r=ed[x];
        }
        build(1,1,n);
        sort(e+1,e+1+Q,comp);
        int ks=1;
        for(int i=1;i<=cnt;++i){
            int t=num[i];
            qx[t].push_back(i);
            int len=qx[t].size();
            if(len==k) change(1,1,qx[t][0],1);
            //printf("sss\n");
            if(len>k){
                change(1,qx[t][len-k-1]+1,qx[t][len-k],1);
                if(len==k+1) change(1,1,qx[t][len-k-1],-1);
                else change(1,qx[t][len-k-2]+1,qx[t][len-k-1],-1);
            }
            while(e[ks].r==i){
                ans1=0;
                search(1,e[ks].l);
                yy[e[ks].rk]=ans1;
                ks++;
            }
        }
        for(int i=1;i<=Q;++i) printf("%d\n",yy[i]);
        if(cse!=T) puts("");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LLL_Amazing/article/details/81512585