题解 P3605 [USACO17JAN]Promotion Counting晋升者计数
Posted ilverene
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P3605 [USACO17JAN]Promotion Counting晋升者计数相关的知识,希望对你有一定的参考价值。
这道题开10倍左右一直MLE+RE,然后尝试着开了20倍就A了。。。窒息
对于这道题目,我们考虑使用线段树合并来做。
所谓线段树合并,就是把结构相同的线段树上的节点的信息合在一起,合并的方式比较类似左偏树什么的。
我们对于每个节点用权值线段树查询大于它的子节点数量,然后把当前节点并到它的父亲上面去。
对于此类型的题目我们通常使用动态开点的线段树(不然炸的没边)。
时间复杂度应该是O(nlogn)
AC代码如下:
455ms 32824kb
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 namespace StandardIO { 6 7 template<typename T> inline void read (T &x) { 8 x=0;T f=1;char c=getchar(); 9 for(; c<‘0‘||c>‘9‘; c=getchar()) if(c==‘-‘) f=-1; 10 for(; c>=‘0‘&&c<=‘9‘; c=getchar()) x=x*10+c-‘0‘; 11 x*=f; 12 } 13 template<typename T>inline void write (T x) { 14 if (x<0) putchar(‘-‘),x*=-1; 15 if (x>=10) write(x/10); 16 putchar(x%10+‘0‘); 17 } 18 19 } 20 21 using namespace StandardIO; 22 23 namespace Solve { 24 25 const int N=100100; 26 27 int n; 28 int cnt; 29 struct node { 30 int id,v; 31 inline bool operator < (const node &x) const { 32 return v<x.v; 33 } 34 }p[N]; 35 vector<int>graph[N]; 36 int tree_node; 37 int val[N],tree[(int)(N*20)],ls[(int)(N*20)],rs[(int)(N*20)],root[N],ans[N]; 38 39 void build (int l,int r,int v,int &root) { 40 if (!root) root=++tree_node; 41 tree[root]++; 42 if (l==r) return; 43 int mid=(l+r)>>1; 44 if (v<=mid) build(l,mid,v,ls[root]); 45 else build(mid+1,r,v,rs[root]); 46 } 47 int query (int l,int r,int v,int root) { 48 if (!root) return 0; 49 if (v<=l) return tree[root]; 50 int mid=(l+r)>>1; 51 if (v<=mid) return query(l,mid,v,ls[root])+query(mid+1,r,v,rs[root]); 52 return query(mid+1,r,v,rs[root]); 53 } 54 int merge (int x,int y) { 55 if (!x||!y) return x+y; 56 int root=++tree_node; 57 tree[root]=tree[x]+tree[y]; 58 ls[root]=merge(ls[x],ls[y]); 59 rs[root]=merge(rs[x],rs[y]); 60 return root; 61 } 62 void dfs (int now) { 63 for (register int i=0; i<graph[now].size(); ++i) { 64 int to=graph[now][i]; 65 dfs(to); 66 root[now]=merge(root[now],root[to]); 67 } 68 ans[now]=query(1,cnt,val[now]+1,root[now]); 69 build(1,cnt,val[now],root[now]); 70 } 71 72 inline void solve () { 73 read(n); 74 for (register int i=1; i<=n; ++i) { 75 read(p[i].v),p[i].id=i; 76 } 77 sort(p+1,p+n+1); 78 for (register int i=1; i<=n; ++i) { 79 if (p[i].v!=p[i-1].v) val[p[i].id]=++cnt; 80 else val[p[i].id]=cnt; 81 } 82 for (register int i=2; i<=n; ++i) { 83 int x;read(x); 84 graph[x].push_back(i); 85 } 86 dfs(1); 87 for (register int i=1; i<=n; ++i) { 88 write(ans[i]),putchar(‘ ‘); 89 } 90 } 91 } 92 93 using namespace Solve; 94 95 int main () { 96 solve(); 97 }
以上是关于题解 P3605 [USACO17JAN]Promotion Counting晋升者计数的主要内容,如果未能解决你的问题,请参考以下文章
洛谷P3605 [USACO17JAN]Promotion Counting晋升者计数
P3605 [USACO17JAN]Promotion Counting P (dsu+线段树)
P3605 [USACO17JAN]Promotion Counting P (线段树合并)
P3605 [USACO17JAN]Promotion Counting P (线段树合并)