[Usaco2017 Jan]Promotion Counting 线段树合并模板/dfs序

两种做法,因为是求整个子树的值域问题所以可以按dfs序把进点和出点的数量作差

#include<bits/stdc++.h>  
//#pragma comment(linker, "/STACK:1024000000,1024000000")   
#include<stdio.h>  
#include<algorithm>  
#include<queue>  
#include<string.h>  
#include<iostream>  
#include<math.h>                    
#include<stack>
#include<set>  
#include<map>  
#include<vector>  
#include<iomanip> 
#include<bitset>
using namespace std;         //
 
#define ll long long  
#define ull unsigned long long
#define pb push_back  
#define FOR(a) for(int i=1;i<=a;i++) 
#define sqr(a) (a)*(a)
#define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))
ll qp(ll a,ll b,ll mod){
    ll t=1;while(b){if(b&1)t=t*a%mod;b>>=1;a=a*a%mod;}return t;
}
struct DOT{ll x;ll y;};
inline void read(int &x){int k=0;char f=1;char c=getchar();for(;!isdigit(c);c=getchar())if(c=='-')f=-1;for(;isdigit(c);c=getchar())k=k*10+c-'0';x=k*f;} 
const int dx[4]={0,0,-1,1};
const int dy[4]={1,-1,0,0};
const int inf=0x3f3f3f3f; 
const ll Linf=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;;
 
const int maxn=1e5+34;
 
int v[maxn];
 
 
int nodecnt,root;
int val[maxn],happen[maxn],l[maxn],r[maxn],rnd[maxn],size[maxn];
 
void maintain(int x){size[x]=size[l[x]]+size[r[x]]+happen[x];}
void rturn(int &k){int t=l[k];l[k]=r[t];r[t]=k;maintain(k);maintain(t);k=t;}
void lturn(int &k){int t=r[k];r[k]=l[t];l[t]=k;maintain(k);maintain(t);k=t;}
void insert1(int &x,int v){ //按大小
    if(!x){
        x=++nodecnt;
        l[x]=r[x]=0;
        val[x]=v;happen[x]=size[x]=1;rnd[x]=rand();return;
    }
    size[x]++;
    if(val[x]==v)happen[x]++;
    else if(v<val[x]){
        insert1(l[x],v);
        if(rnd[l[x]]<rnd[x])rturn(x);
    }else{
        insert1(r[x],v);
        if(rnd[r[x]]<rnd[x])lturn(x);
    }
}
void del(int &x,int v){
    if(!x)return;
    if(val[x]==v){
        if(happen[x]>1){happen[x]--;size[x]--;return;}
        if(!l[x]||!r[x])x=l[x]+r[x];
        else if(rnd[l[x]]<rnd[r[x]]){rturn(x);del(x,v);}
        else{lturn(x);del(x,v);}
    }else{
        size[x]--;
        if(v<val[x])del(l[x],v);
        else del(r[x],v);
    }
}
int rnk(int x,int v){
    if(!x)return 0;
    if(val[x]==v)return size[l[x]]+happen[x];
    else if(v<val[x])return rnk(l[x],v);
    else return size[l[x]]+happen[x]+rnk(r[x],v);
}
int kth(int x,int k){
    if(!x)return 0;
    if(k<=size[l[x]])return kth(l[x],k);
    else if(k>size[l[x]]+happen[x])
        return kth(r[x],k-size[l[x]]-happen[x]);
    else return val[x];
}
int ans;
void pre(int x,int v){
    if(!x)return;
    if(v>val[x])ans=x,pre(r[x],v);
    else pre(l[x],v);
}
void suf(int x,int v){
    if(!x)return;
    if(v<val[x])ans=x,suf(l[x],v);
    else suf(r[x],v);
}
 
vector<int>G[maxn];
int Ans[maxn];
 
void dfs(int x){
    insert1(root,v[x]);
    int t1=nodecnt-rnk(root,v[x]);
    for(int i=0;i<G[x].size();i++){
        dfs(G[x][i]);
    }
    int t2=nodecnt-rnk(root,v[x]);
    Ans[x]=t2-t1;
 
}
 
int main(){
    int n;scanf("%d",&n);
    FOR(n)scanf("%d",&v[i]);
    for(int i=2,x;i<=n;i++){
        scanf("%d",&x);
        G[x].pb(i);
    }
    dfs(1);
    for(int i=1;i<=n;i++)printf("%d\n",Ans[i]);
}


一开始没看到各点权不同把平衡树的求rank改了下

-------------------------------------------------------------------------------------------------------------------------------------------------------

另一种做法是每个点做一个权值线段树,然后把这些权值线段树合并起来

由于线段树只要参数固定生成形状就固定,所以一开始是n个log长的链,每个节点代表一个区间,节点权是出现次数

合并的时候因为大家结构一样所以就左边+左边,右边+右边

空间时间都是nlogn

#include<bits/stdc++.h>  
//#pragma comment(linker, "/STACK:1024000000,1024000000")   
#include<stdio.h>  
#include<algorithm>  
#include<queue>  
#include<string.h>  
#include<iostream>  
#include<math.h>                    
#include<stack>
#include<set>  
#include<map>  
#include<vector>  
#include<iomanip> 
#include<bitset>
using namespace std;         //

#define ll long long  
#define ull unsigned long long
#define pb push_back  
#define FOR(a) for(int i=1;i<=a;i++) 
#define sqr(a) (a)*(a)
#define dis(a,b) sqrt(sqr(a.x-b.x)+sqr(a.y-b.y))
ll qp(ll a,ll b,ll mod){
	ll t=1;while(b){if(b&1)t=t*a%mod;b>>=1;a=a*a%mod;}return t;
}
struct DOT{ll x;ll y;};
inline void read(int &x){int k=0;char f=1;char c=getchar();for(;!isdigit(c);c=getchar())if(c=='-')f=-1;for(;isdigit(c);c=getchar())k=k*10+c-'0';x=k*f;} 
const int dx[4]={0,0,-1,1};
const int dy[4]={1,-1,0,0};
const int inf=0x3f3f3f3f; 
const ll Linf=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;;

const int maxn=2e6+34;

int n,a[maxn],b[maxn];
vector<int>G[maxn];

int seg;
int tree[maxn],lson[maxn],rson[maxn];

int root[maxn],ans[maxn];

void pushup(int rt){tree[rt]=tree[lson[rt]]+tree[rson[rt]];}
void build(int &rt,int l,int r,int pos){
	rt=++seg;
	if(l==r){
		tree[rt]=1;return;
	}
	int m=l+r>>1;
	if(pos<=m)build(lson[rt],l,m,pos);
	else build(rson[rt],m+1,r,pos);
	pushup(rt);
}
int query(int rt,int l,int r,int a,int b){
	if(a<=l&&b>=r)return tree[rt];
	int m=l+r>>1;
	int ret=0;
	if(a<=m)ret+=query(lson[rt],l,m,a,b);
	if(b>m)ret+=query(rson[rt],m+1,r,a,b);
	return ret;
}
int merge(int x,int y){
	if(!x)return y;if(!y)return x;
	lson[x]=merge(lson[x],lson[y]);
	rson[x]=merge(rson[x],rson[y]);
	pushup(x);
	return x;
}

void dfs(int u){
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		dfs(v);
		root[u]=merge(root[u],root[v]);
	}
	ans[u]=query(root[u],1,n,a[u]+1,n);
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	int tot=unique(b+1,b+1+n)-b-1;

	for(int i=1;i<=n;i++){
		a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
	}
	for(int i=2;i<=n;i++){
		int x;scanf("%d",&x);
		G[x].pb(i);
	}
	for(int i=1;i<=n;i++){
		build(root[i],1,n,a[i]);
	}
	dfs(1);
	for(int i=1;i<=n;i++){
		printf("%d\n",ans[i]);
	}
}

posted @ 2018-03-01 22:31  Drenight  阅读(190)  评论(0编辑  收藏  举报