[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]); } }