1. 程式人生 > >題解 P3605 【[USACO17JAN]Promotion Counting晉升者計數】

題解 P3605 【[USACO17JAN]Promotion Counting晉升者計數】

bit 計數 typename 查詢 stand name query count 節點數

這道題開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(\n); 89 } 90 } 91 } 92 93 using namespace Solve; 94 95 int main () { 96 solve(); 97 }

題解 P3605 【[USACO17JAN]Promotion Counting晉升者計數】