线段树合并 || 树状数组 || 离散化 || BZOJ 4756: [Usaco2017 Jan]Promotion Counting || Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数
题面:P3605 [USACO17JAN]Promotion Counting晋升者计数
题解:这是一道万能题,树状数组 || 主席树 || 线段树合并 || 莫队套分块 || 线段树 都可以写。。记得离散化
线段树合并版:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=(1e5)+50; 7 int N,num_edge=0,edge_head[maxn],W[maxn],lsh_cnt=0,num_treenode=0; 8 int root[maxn],ans[maxn],u; 9 struct A_{int id,data;}A[maxn]; 10 inline bool cmp(const A_&a,const A_&b){return a.data<b.data;} 11 struct Edge{int to,nx;}edge[maxn]; 12 inline void Add_edge(int from,int to){ 13 edge[++num_edge].nx=edge_head[from]; 14 edge[num_edge].to=to; 15 edge_head[from]=num_edge; 16 return; 17 } 18 struct Tree{int lc,rc,l,r,cnt;}t[maxn*20]; 19 inline void Build(int x,int l,int r,int q){ 20 t[x].l=l;t[x].r=r;int mid=(l+r)>>1; 21 if(l==r&&l==q){ 22 t[x].cnt=1; 23 return; 24 } 25 if(q<=mid)Build(t[x].lc=++num_treenode,l,mid,q); 26 else Build(t[x].rc=++num_treenode,mid+1,r,q); 27 t[x].cnt=t[t[x].lc].cnt+t[t[x].rc].cnt; 28 return; 29 } 30 inline int Merge(int u,int v){ 31 if(!u)return v; 32 if(!v)return u; 33 int l=t[u].l,r=t[u].r; 34 if(l==r){ 35 t[u].cnt+=t[v].cnt; 36 return u; 37 } 38 t[u].lc=Merge(t[u].lc,t[v].lc); 39 t[u].rc=Merge(t[u].rc,t[v].rc); 40 t[u].cnt=t[t[u].lc].cnt+t[t[u].rc].cnt; 41 return u; 42 } 43 inline void Query(int g,int x,int ql,int qr){ 44 int l=t[x].l,r=t[x].r,mid=(l+r)>>1,lc=t[x].lc,rc=t[x].rc; 45 if(x==0)return; 46 if(ql<=l&&r<=qr){ 47 ans[g]+=t[x].cnt; 48 return; 49 } 50 if(ql<=mid)Query(g,lc,ql,qr); 51 if(qr>mid) Query(g,rc,ql,qr); 52 return; 53 } 54 inline void Dfs(int x){ 55 for(int i=edge_head[x];i;i=edge[i].nx){ 56 int y=edge[i].to; 57 Dfs(y); 58 root[x]=Merge(root[x],root[y]); 59 } 60 if(W[x]+1>lsh_cnt)ans[x]=0; 61 else Query(x,root[x],W[x]+1,lsh_cnt); 62 return; 63 } 64 int main(){ 65 scanf("%d",&N); 66 for(int i=1;i<=N;i++){ 67 scanf("%d",&A[i].data); 68 A[i].id=i; 69 } 70 sort(A+1,A+N+1,cmp); 71 W[A[1].id]=++lsh_cnt; 72 for(int i=2;i<=N;i++) 73 if(A[i].data!=A[i-1].data)W[A[i].id]=++lsh_cnt; 74 else W[A[i].id]=lsh_cnt; 75 for(int i=2;i<=N;i++){ 76 scanf("%d",&u); 77 Add_edge(u,i); 78 } 79 for(int i=1;i<=N;i++)Build(root[i]=++num_treenode,1,lsh_cnt+5,W[i]); 80 Dfs(1); 81 for(int i=1;i<=N;i++)printf("%d\n",ans[i]); 82 return 0; 83 }
树状数组版:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define ll long long 6 #define re register 7 using namespace std; 8 inline int rd(){ 9 int x=0;char c=getchar(); 10 while(c<'0'||c>'9')c=getchar(); 11 while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} 12 return x; 13 } 14 const int maxn=1e5; 15 int N,P[maxn+5],cnt=0,num_edge=0,edge_head[maxn+5],F,C[maxn+5]; 16 ll ans[maxn+5]; 17 struct Edge{ 18 int to,nx; 19 }edge[maxn+5]; 20 struct Node{ 21 int x,id; 22 }A[maxn+50]; 23 inline bool cmp(const Node&a,const Node&b){ 24 if(a.x<b.x)return 1; 25 return 0; 26 } 27 inline int Find(int x){ 28 re ll ans=0; 29 for(;x<=cnt;x+=x&(-x))ans+=C[x]; 30 return ans; 31 } 32 inline void Update(int x){ 33 for(;x>0;x-=x&(-x))C[x]++; 34 return; 35 } 36 inline void Dfs(int x){ 37 ans[x]-=Find(P[x]); 38 for(re int i=edge_head[x];i;i=edge[i].nx) Dfs(edge[i].to); 39 ans[x]+=Find(P[x]); 40 Update(P[x]); 41 return; 42 } 43 int main(){ 44 N=rd(); 45 for(re int i=1;i<=N;i++){ 46 A[i].x=rd(); 47 A[i].id=i; 48 } 49 sort(A+1,A+N+1,cmp); 50 for(re int i=1;i<=N;i++){ 51 if(i==1||A[i].x!=A[i-1].x)cnt++; 52 P[A[i].id]=cnt; 53 } 54 for(re int i=2;i<=N;i++){ 55 scanf("%d",&F); 56 edge[++num_edge].nx=edge_head[F]; 57 edge[num_edge].to=i; 58 edge_head[F]=num_edge; 59 } 60 Dfs(1); 61 for(re int i=1;i<=N;i++)printf("%lld\n",ans[i]); 62 return 0; 63 }
By:AlenaNuna