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

猜你喜欢

转载自www.cnblogs.com/ilverene/p/9841094.html