题目链接:https://ac.nowcoder.com/acm/contest/4010/E
题目分析:
错误解法:看一眼就知道要用set,于是我一开始非常莽的跑了一发O(n*n*logn)的假算法,过了70%的数据,就是对于每次操作,新添加的树合并到重儿子上,合并完之后,用vector把set里的元素全部复制(提取)出来,再O(n)扫一发vector序列,想想吧,1e5大小的肯定爆TLE了.
1 #include2 #define ll long long 3 #define rep(i,a,n) for(int i=a;i<=n;i++) 4 #define per(i,n,a) for(int i=n;i>=a;i--) 5 #define endl '\n' 6 #define eps 0.000000001 7 #define pb push_back 8 #define mem(a,b) memset(a,b,sizeof(a)) 9 #define IO ios::sync_with_stdio(false);cin.tie(0); 10 using namespace std; 11 const int INF=0x3f3f3f3f; 12 const ll inf=0x3f3f3f3f3f3f3f3f; 13 const int mod=1e9+7; 14 const int maxn=1e5+5; 15 int tot,head[maxn]; 16 struct E{ 17 int to,next; 18 }edge[maxn<<1]; 19 void add(int u,int v){ 20 edge[tot].to=v; 21 edge[tot].next=head[u]; 22 head[u]=tot++; 23 } 24 int n; 25 int siz[maxn],son[maxn],dep[maxn]; 26 void dfs1(int u,int f){ 27 dep[u]=dep[f]+1; 28 siz[u]=1; 29 for(int i=head[u];i!=-1;i=edge[i].next){ 30 int v=edge[i].to; 31 if(v==f) continue; 32 dfs1(v,u); 33 siz[u]+=siz[v]; 34 if(siz[v]>siz[son[u]]) son[u]=v; 35 } 36 } 37 int flag;set<int> s;ll ans[maxn]; 38 void count(int u,int f,int val){ 39 if(val==1) s.insert(u); 40 else s.erase(u); 41 for(int i=head[u];i!=-1;i=edge[i].next){ 42 int v=edge[i].to; 43 if(v==f||v==flag) continue; 44 count(v,u,val); 45 } 46 } 47 void dfs(int u,int f,int keep){ 48 for(int i=head[u];i!=-1;i=edge[i].next){ 49 int v=edge[i].to; 50 if(v==f||v==son[u]) continue; 51 dfs(v,u,0); 52 } 53 if(son[u]){ 54 dfs(son[u],u,1); 55 flag=son[u]; 56 } 57 count(u,f,1); 58 vector<int> vec; 59 for(auto it:s) vec.push_back(it); 60 ll sum=0; 61 for(int i=0;i 1;i++){ 62 sum+=(vec[i+1]-vec[i])*(vec[i+1]-vec[i]); 63 } 64 ans[u]=sum; 65 flag=0; 66 if(!keep){ 67 count(u,f,-1); 68 } 69 } 70 int main(){ 71 cin>>n;mem(head,-1); 72 rep(i,2,n){ 73 int x;cin>>x; 74 add(x,i);add(i,x); 75 } 76 dfs1(1,0); 77 dfs(1,0,0); 78 rep(i,1,n){ 79 cout< endl; 80 } 81 }
正确解法:借助树上启发式合并不断传递的思想,对于每次更新的一个数,我们都可以在logn的时间复杂度内解决,具体实现就是先二分找到这个操作数的位置,并取出其相邻的两个数,减去之前的贡献,累加上新增加的贡献即可完成贡献(这一步很妙!!我感觉可以出一下这方面的坑新生hhh),这样总的时间复杂度就是O(n*logn*logn)了。这里对STL中set容器的运用我又加深了一步嘻嘻
1 #include2 #define ll long long 3 #define rep(i,a,n) for(int i=a;i<=n;i++) 4 #define per(i,n,a) for(int i=n;i>=a;i--) 5 #define endl '\n' 6 #define eps 0.000000001 7 #define pb push_back 8 #define mem(a,b) memset(a,b,sizeof(a)) 9 #define IO ios::sync_with_stdio(false);cin.tie(0); 10 using namespace std; 11 const int INF=0x3f3f3f3f; 12 const ll inf=0x3f3f3f3f3f3f3f3f; 13 const int mod=1e9+7; 14 const int maxn=1e5+5; 15 int tot,head[maxn]; 16 struct E{ 17 int to,next; 18 }edge[maxn<<1]; 19 void add(int u,int v){ 20 edge[tot].to=v; 21 edge[tot].next=head[u]; 22 head[u]=tot++; 23 } 24 int n; 25 int siz[maxn],son[maxn],dep[maxn]; 26 void dfs1(int u,int f){ 27 dep[u]=dep[f]+1; 28 siz[u]=1; 29 for(int i=head[u];i!=-1;i=edge[i].next){ 30 int v=edge[i].to; 31 if(v==f) continue; 32 dfs1(v,u); 33 siz[u]+=siz[v]; 34 if(siz[v]>siz[son[u]]) son[u]=v; 35 } 36 } 37 int flag;set<int> s;ll ans[maxn],sum; 38 void in(int num){ 39 set<int>::iterator it=s.lower_bound(num),start=s.begin(),end=s.end(); 40 end--; 41 auto pre=it,next=it; 42 if(pre!=start) pre--; 43 if(next!=end) next++; 44 if(it!=next&&it!=pre){ 45 sum-=1LL*(*next-*pre)*(*next-*pre); 46 sum+=1LL*(*next-*it)*(*next-*it); 47 sum+=1LL*(*it-*pre)*(*it-*pre); 48 } 49 else if(it==next&&it!=pre){ 50 sum+=1LL*(*it-*pre)*(*it-*pre); 51 } 52 else if(it==pre&&it!=next){ 53 sum+=1LL*(*next-*it)*(*next-*it); 54 } 55 } 56 void out(int num){ 57 set<int>::iterator it=s.lower_bound(num),start=s.begin(),end=s.end(); 58 end--; 59 auto pre=it,next=it; 60 if(pre!=start) pre--; 61 if(next!=end) next++; 62 if(it!=next&&it!=pre){ 63 sum+=1LL*(*next-*pre)*(*next-*pre); 64 sum-=1LL*(*next-*it)*(*next-*it); 65 sum-=1LL*(*it-*pre)*(*it-*pre); 66 } 67 else if(it==next&&it!=pre){ 68 sum-=1LL*(*it-*pre)*(*it-*pre); 69 } 70 else if(it==pre&&it!=next){ 71 sum-=1LL*(*next-*it)*(*next-*it); 72 } 73 } 74 void count(int u,int f,int val){ 75 if(val==1) s.insert(u),in(u); 76 else out(u),s.erase(u); 77 for(int i=head[u];i!=-1;i=edge[i].next){ 78 int v=edge[i].to; 79 if(v==f||v==flag) continue; 80 count(v,u,val); 81 } 82 } 83 void dfs(int u,int f,int keep){ 84 for(int i=head[u];i!=-1;i=edge[i].next){ 85 int v=edge[i].to; 86 if(v==f||v==son[u]) continue; 87 dfs(v,u,0); 88 } 89 if(son[u]){ 90 dfs(son[u],u,1); 91 flag=son[u]; 92 } 93 count(u,f,1); 94 ans[u]=sum; 95 flag=0; 96 if(!keep){ 97 count(u,f,-1);sum=0; 98 } 99 } 100 int main(){ 101 cin>>n;mem(head,-1); 102 rep(i,2,n){ 103 int x;cin>>x; 104 add(x,i);add(i,x); 105 } 106 dfs1(1,0); 107 dfs(1,0,0); 108 rep(i,1,n){ 109 cout< endl; 110 } 111 }