zoukankan      html  css  js  c++  java
  • Wannafly Day2 E 阔力梯的树(树上启发式合并)

    题目链接:https://ac.nowcoder.com/acm/contest/4010/E

    题目分析:

    错误解法:看一眼就知道要用set,于是我一开始非常莽的跑了一发O(n*n*logn)的假算法,过了70%的数据,就是对于每次操作,新添加的树合并到重儿子上,合并完之后,用vector把set里的元素全部复制(提取)出来,再O(n)扫一发vector序列,想想吧,1e5大小的肯定爆TLE了.

     1 #include<bits/stdc++.h>
     2 #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 '
    '
     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<vec.size()-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<<ans[i]<<endl;
    80     }
    81 }
    View Code

    正确解法:借助树上启发式合并不断传递的思想,对于每次更新的一个数,我们都可以在logn的时间复杂度内解决,具体实现就是先二分找到这个操作数的位置,并取出其相邻的两个数,减去之前的贡献,累加上新增加的贡献即可完成贡献(这一步很妙!!我感觉可以出一下这方面的坑新生hhh),这样总的时间复杂度就是O(n*logn*logn)了。这里对STL中set容器的运用我又加深了一步嘻嘻

      1 #include<bits/stdc++.h>
      2 #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 '
    '
      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<<ans[i]<<endl;
    110     }
    111 }
    View Code
  • 相关阅读:
    js原生碰撞检测
    基于栈的指令集与基于寄存器的指令集
    偏向锁,轻量级锁
    java 内存模型
    JVM即时编译器
    动态分配
    静态分配
    栈帧笔记
    类加载器
    类加载过程
  • 原文地址:https://www.cnblogs.com/Anonytt/p/13080989.html
Copyright © 2011-2022 走看看