您的位置:首页 > 其它

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

2018-03-01 22:30 417 查看
两种做法,因为是求整个子树的值域问题所以可以按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改了下
-------------------------------------------------------------------------------------------------------------
4000
------------------------------------------

另一种做法是每个点做一个权值线段树,然后把这些权值线段树合并起来
由于线段树只要参数固定生成形状就固定,所以一开始是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]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: