SCUT106 花式AC 主席树版本

Posted aya-uchida

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SCUT106 花式AC 主席树版本相关的知识,希望对你有一定的参考价值。

网址:https://scut.online/p/106

题意:

给出一个点权树以$1$为根节点,求子树有几个节点的权值小于等于$k$。

题解:

主席树版本,先对树$dfs$求出第一次进入某节点的时间戳,然后同时处理出子树的节点数,然后求出的$dfs$序中某节点的时间戳后长度为该节点的子树的大小$-1$就是这个节点的子树对应的序列,在主席树上求个数即可。原理类似于求区间第k大,只不过是每棵主席树都保存了序列前$m(1 \leq m \leq n)$个数大小是$[1,n]$数的总个数,然后查询时查询区间中的$[1,k]$的数的个数即可。由于本题数值过大,因为权值是离散化的,所以输入的$k$也要离散化,找到小于等于k的第一个数。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN=100005;
struct cheiftree

    struct node
    
        int l,r,sum;
    ;
    node tr[MAXN*20];
    int rt[MAXN];
    int cnt=0;
    void init()
    
        cnt=0;
    
    void build(int &rt,int l,int r)
    
        rt=++cnt;
        tr[rt].sum=0;
        int m=(l+r)/2;
        if(l==r)
            return;
        build(tr[rt].l,l,m);
        build(tr[rt].r,m+1,r);
    
    void update(int &rt,int l,int r,int k)
    
        tr[++cnt]=tr[rt];
        rt=cnt;
        ++tr[rt].sum;
        if(l==r)
            return;
        int m=(l+r)/2;
        if(k<=m)
            update(tr[rt].l,l,m,k);
        else  
            update(tr[rt].r,m+1,r,k);
    
    int query(int rl,int rr,int l,int r,int val)
    
        if(l==r)
            return tr[rr].sum-tr[rl].sum;
        int m=(l+r)/2;
        if(val<=m)
            return query(tr[rl].l,tr[rr].l,l,m,val);
        else if(val>m)
            return tr[tr[rr].l].sum-tr[tr[rl].l].sum+query(tr[rl].r,tr[rr].r,m+1,r,val);
    
;
cheiftree tr;
int in[MAXN],a[MAXN],b[MAXN],size[MAXN],vis[MAXN];
int cnt=0;
vector<int>E[MAXN];
void print()

    for(int i=1;i<=tr.cnt;++i)
        cout<<tr.tr[i].l<<" "<<tr.tr[i].r<<" "<<tr.tr[i].sum<<endl;

void dfs(int u)

    in[u]=++cnt;
    size[u]=1;
    vis[cnt]=u;
    for(auto &i:E[u])
    
        dfs(i);
        size[u]+=size[i];
    

void init(int n)

    cnt=0;
    for(int i=1;i<=n;++i)
        E[i].clear();

int main()

    int n,t,m;
    while(~scanf("%d%d",&n,&m))
    
        init(n);
        for(int i=1;i<n;++i)
        
            scanf("%d",&t);
            E[t].push_back(i+1);
        
        dfs(1);
        //for(int i=1;i<=cnt;++i)
            //cout<<in[i]<<" "<<size[i]<<" "<<vis[i]<<endl;
        for(int i=1;i<=n;++i)
        
            scanf("%d",&a[i]);
            b[i]=a[i];
        
        sort(b+1,b+1+n);
        int nnew=unique(b+1,b+1+n)-b-1;
        tr.init();
        tr.build(tr.rt[0],1,nnew);
        for(int i=1;i<=n;++i)
        
            tr.rt[i]=tr.rt[i-1];
            int pos=lower_bound(b+1,b+1+nnew,a[vis[i]])-b;
            tr.update(tr.rt[i],1,nnew,pos);
        
        //print();
        for(int i=0;i<m;++i)
        
            scanf("%d%d",&n,&t);
            int k=upper_bound(b+1,b+1+nnew,t)-b-1;
            int l=tr.rt[in[n]-1],r=tr.rt[in[n]+size[n]-1];
            printf("%d\n",tr.query(l,r,1,nnew,k));
        
    
    return 0;

 

以上是关于SCUT106 花式AC 主席树版本的主要内容,如果未能解决你的问题,请参考以下文章

主席树模板之历史版本

CodeForces 547E:Mike and Friends(AC自动机+DFS序+主席树)

主席树模板

可持久化线段树/主席树(静态)

主席树

主席树