题解 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 (线段树合并)

P3605 [USACO17JAN]Promotion Counting P(树状数组)

P3605 [USACO17JAN]Promotion Counting P(树状数组)