BZOJ[4756][Usaco2017 Jan]Promotion Counting 线段树合并

来源:互联网 发布:前端页面优化方案 编辑:程序博客网 时间:2024/05/22 05:48

题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=4756

裸的线段树合并
对于每个点建一个权值线段树

这里采用了动态开点,常数较大(线段树范围是1~MAXN),但是省略了离散化

代码如下:

#include<ctype.h>#include<cstdio>#define N 100050using namespace std;const int INF=1000000000;///数最大这么多inline int read(){    int x=0,f=1;char c;    do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));    return x*f;}int top,n,x;int ans[N],fir[N],a[N];struct Edge{    int to,nex;    Edge(int _=0,int __=0):to(_),nex(__){}}nex[N];struct Node{    int sum,l,r;    Node *ls,*rs;    inline void maintain() {        sum=ls->sum+rs->sum;    }    Node(int,int);}*root[N],*null;///定义一个null,可以省略好多问题(同平衡树那个)Node::Node(int _=0,int __=0):l(_),r(__){    sum=0;    ls=rs=null;}inline void add(int x,int y){    nex[++top]=Edge(y,fir[x]);    fir[x]=top;}void Add(int x,Node *&k,int L,int R){///L,R记录左右节点(动态开点用的)    if(k==null) k=new Node(L,R);///动态开点,如果原先没有这个点就加上    if(k->l==k->r){        k->sum++;        return;    }    int mid=L+R>>1;    if(x<=mid) Add(x,k->ls,L,mid);    else Add(x,k->rs,mid+1,R);    k->maintain();}int Query(int l,int r,Node *k){    if(k==null) return 0;    if(k->l>=l && k->r<=r){        return k->sum;    }    int mid=k->l+k->r>>1,t;    if(mid>=r) t=Query(l,r,k->ls);    else if(mid<l) t=Query(l,r,k->rs);    else t=Query(l,r,k->ls)+Query(l,r,k->rs);    k->maintain();    return t;}void Merge(Node *&x,Node *&y){    if(y==null) return;    if(x==null){        x=y;        return;    }    x->sum+=y->sum;    Merge(x->ls,y->ls);Merge(x->rs,y->rs);}void Debug(Node *x){///调试orz..    if(x->ls!=null) Debug(x->ls);    if(x->rs!=null) Debug(x->rs);    printf("%d %d %d\n",x->l,x->r,x->sum);}void dfs(int x){    for(int i=fir[x];i;i=nex[i].nex){        dfs(nex[i].to);        Merge(root[x],root[nex[i].to]);///求出子树答案后,合并到本节点上    }    ans[x]=Query(a[x]+1,INF,root[x]);}int main(){    null=new Node(-1,-1);    null->ls=null->rs=null;    null->sum=0;    n=read();    for(int i=1;i<=n;i++)        a[i]=read(),root[i]=null;    for(int i=2;i<=n;i++){        x=read();        add(x,i);    }    for(int i=1;i<=n;i++)        Add(a[i],root[i],1,INF);    dfs(1);    for(int i=1;i<=n;i++){        printf("%d\n",ans[i]);    }return 0;}
阅读全文
0 0
原创粉丝点击