您的位置:首页 > 其它

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

2017-04-12 16:13 477 查看
题目大意:给出一棵有根树,每个点有一个权值,问对于每一个点的子树中比这个点大的点的个数。

首先权值很大需要离散化。(2017-7-13UPD:不用离散化也可反正也是动态开点

对于每一个点建一个权值线段树。遍历每一棵子树,然后将子树的线段树合并到自己的线段树上,在查询之后将自己插入。时间复杂度O(nlogn)

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100005
using namespace std;
struct Node {
Node *ch[2];
int l,r,sum;
Node(int _l,int _r):l(_l),r(_r) {
sum=0;
ch[0]=ch[1]=NULL;
}
Node() {}
void maintain() {
sum=0;
if(ch[0]) sum+=ch[0]->sum;
if(ch[1]) sum+=ch[1]->sum;
return ;
}
void* operator new (size_t) {
static Node *mempool,*C;
if(mempool==C) mempool=(C=new Node[1<<20])+(1<<20);
return C++;
}
}*root
;
struct Edge {
int to,nxt;
Edge() {}
Edge(int _to,int _nxt):to(_to),nxt(_nxt) {}
}e
;
int n,m,tot=-1,fir
,a
,b
,ans
;
void Add_Edge(int x,int y) {
e[++tot]=Edge(y,fir[x]), fir[x]=tot;
return ;
}
void Merge(Node*& x,Node*& y) {
if(!y) return ;
if(!x) {
x=y;
return ;
}
x->sum+=y->sum;
Merge(x->ch[0],y->ch[0]), Merge(x->ch[1],y->ch[1]);
return ;
}
void Insert(Node*& o,int v,int L,int R) {
if(!o) o=new Node(L,R);
if(o->l==o->r) {
o->sum++;
return ;
}
int mid=L+R>>1;
if(v<=mid) Insert(o->ch[0],v,L,mid);
else Insert(o->ch[1],v,mid+1,R);
o->maintain();
return ;
}
int Query(Node* o,int v) {
if(!o) return 0;
if(v==o->r) return o->sum;
int mid=o->l+o->r>>1;
if(v<=mid) return Query(o->ch[0],v);
return (o->ch[0] ? o->ch[0]->sum : 0)+Query(o->ch[1],v);
}
void dfs(int x) {
for(int i=fir[x];~i;i=e[i].nxt) {
dfs(e[i].to);
Merge(root[x],root[e[i].to]);
}
ans[x]=Query(root[x],n-a[x]);
Insert(root[x],n-a[x]+1,1,n);
return ;
}
int main() {
memset(fir,-1,sizeof fir);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i), b[i]=a[i];
sort(b+1,b+n+1);
m=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+m,a[i])-b;
for(int i=2;i<=n;i++) {
int x;
scanf("%d",&x);
Add_Edge(x,i);
}
dfs(1);
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: