Codeforces 1009F Dominant Indices

题面

http://codeforces.com/contest/1009/problem/F

题解

启发式合并

这是我做的第一道启发式合并题 感觉如果以前做过启发式合并的题的话 这题可以一眼秒掉

就是个模板题吧

唯一的问题就在于怎么从儿子更新到父亲

我使用了一个map去记录

但是如果用map会不会超时呢?

启发式合并一个log+map一个log,1e6就过不去了

但是这道题比较特殊 我们会发现 正常的启发式合并 每个点记录的信息是与子树大小线性相关

但是这道题 记录的信息与子树深度线性相关

据CF官方题解说 因为合并两个数组的时候 相当于destroy掉小的数组,是O(size of small array)的

然后就证完了?(还是不能理解)

启发式合并复杂度证明:

算法的耗时来自于对查询的回答与各结点对cnt[]数组的操作。由于每次查询都是O(1)的,所以查询的总复杂度为O(m),可以忽略。考虑结点u对cnt[]数组的操作次数,设u的祖先从近到远依次为w_1,w_2,...,w_t。处理子树u时,结点u第一次对cnt[]数组进行操作,而结点u下一次对cnt[]数组进行操作,发生在u下一次不在某个祖先的儿子子树中最大的那棵中时,我们来说明这样的事只能发生O(lgn)次。若u不在w_k的儿子子树中最大的那棵中,则有size(w_k-1)*2≤size(w_k),由于size(w_t)=n,所以这样的事(u不在w_k的儿子子树中最大的那棵中)只能发生O(lgn)次。综上,各节点对cnt[]数组的操作次数为O(nlgn)。

 

Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 ll read(){
 6     ll x=0,f=1;char c=getchar();
 7     while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
 8     while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
 9     return x*f;
10 }
11 
12 const int maxn=1000100;
13 int n;
14 int head[maxn],to[maxn*2],nxt[maxn*2],cnt;
15 map<int,int> m[maxn];
16 int mx[maxn],son[maxn],dep[maxn];
17 int ans[maxn];
18 int mxd[maxn];
19 
20 void addedge(int a,int b){
21     to[++cnt]=b,nxt[cnt]=head[a],head[a]=cnt;
22     to[++cnt]=a,nxt[cnt]=head[b],head[b]=cnt;
23 }
24 
25 void dfs1(int x,int fa=1){
26     mx[x]=1;dep[x]=dep[fa]+1;
27     for(int i=head[x];i;i=nxt[i]){
28         int v=to[i];
29         if(v==fa) continue;
30         dfs1(v,x);
31         mx[x]=max(mx[x],mx[v]+1);
32         if(mx[v]>mx[son[x]]) son[x]=v;
33     }
34 }
35 
36 void dfs2(int x,int fa=1){
37     for(int i=head[x];i;i=nxt[i]){
38         int v=to[i];
39         if(v==fa) continue;
40         dfs2(v,x);
41     }
42     if(son[x]){
43         swap(m[x],m[son[x]]);
44         m[x][dep[x]]=1;
45         mxd[x]=mxd[son[x]];
46         ans[x]=ans[son[x]]+1;
47         if(mxd[x]==1) ans[x]=0;
48     }
49     else{
50         m[x][dep[x]]=1;
51         mxd[x]=1;
52         return;
53     }
54     for(int i=head[x];i;i=nxt[i]){
55         int v=to[i];
56         if(v==fa || v==son[x]) continue;
57         for(map<int,int>::iterator it=m[v].begin();it!=m[v].end();it++){
58             int k=it->first;
59             m[x][k]+=(it->second);
60             if(m[x][k]>mxd[x]){
61                 mxd[x]=m[x][k];
62                 ans[x]=k-dep[x];
63             }
64             if(m[x][k]==mxd[x]){
65                 ans[x]=min(ans[x],k-dep[x]);
66             }
67         }
68     }
69 }
70 
71 int main(){
72 #ifdef LZT
73     freopen("in","r",stdin);
74 #endif
75     n=read();
76     for(int i=1;i<n;i++){
77         int x=read(),y=read();
78         addedge(x,y);
79     }
80     dfs1(1);
81     //for(int i=1;i<=n;i++)
82     //    cout<<son[i]<<' '<<dep[i]<<endl;
83     dfs2(1);
84     for(int i=1;i<=n;i++)
85         printf("%d\n",ans[i]);
86     return 0;
87 }

 

Review

动机似乎非常显然。。。

 

posted @ 2018-08-03 22:20  wawawa8  阅读(356)  评论(0编辑  收藏  举报