题面
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 ",ans[i]); 86 return 0; 87 }
Review
动机似乎非常显然。。。