zoukankan      html  css  js  c++  java
  • [loj2553]暴力写挂

    边分治模板题

    (第一次写边分治就记一下吧)

    对式子变形,即为$frac{dep_{x}+dep_{y}+dis(x,y)}{2}-dep'_{lca'(x,y)}$

    通过增加节点使每一个点的度数都不超过3,不难证明此时总存在一条边,假设其将其删除后两连通块大小分别为$x$和$y$,则有$yle 2x+1$且$xle 2y+1$

    由此,每次找到一条满足此条件的边并拆分,显然层数为$o(log n)$,每一层将(到对应连通块根的)距离加入深度并在第二课树上建立虚树,然后lca为某点的最大新深度和即可

    时间复杂度为$o(nlog^{2}n)$,可以通过

    当然如果将虚树(排序和求lca)做到线性,复杂度即可做到$o(nlog n)$,但意义不大

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 400005
      4 #define ll long long
      5 #define vi vector<int>
      6 #define fi first
      7 #define se second
      8 struct Edge{
      9     int nex,to,len; 
     10 };
     11 int n;
     12 ll ans,val[N];
     13 ll calc(vi x,vi y);
     14 namespace T1{
     15     int m,E,rt,x,y,z,head[N<<1],sz[N<<1],vis[N<<1];
     16     ll dep[N<<1];
     17     vi v,vx,vy;
     18     vector<pair<int,int> >e[N<<1];
     19     Edge edge[N<<2];
     20     void add(int x,int y,int z){
     21         edge[E]=Edge{head[x],y,z};
     22         head[x]=E++;
     23     }
     24     void dfs(int k,int fa,ll s){
     25         dep[k]=s;
     26         for(int i=head[k];i!=-1;i=edge[i].nex)
     27             if (edge[i].to!=fa)dfs(edge[i].to,k,s+edge[i].len);
     28         v.clear();
     29         for(int i=head[k];i!=-1;i=edge[i].nex)
     30             if (edge[i].to!=fa)v.push_back(edge[i].to);
     31         int lst=k;
     32         for(int i=0;i+2<v.size();i++){
     33             e[lst].push_back(make_pair(v[i],dep[v[i]]-dep[k]));
     34             e[lst].push_back(make_pair(++m,0));
     35             lst=m;
     36         }
     37         if (v.size()){
     38             e[lst].push_back(make_pair(v.back(),dep[v.back()]-dep[k]));
     39             v.pop_back();
     40             if (v.size())e[lst].push_back(make_pair(v.back(),dep[v.back()]-dep[k]));
     41         }
     42     }
     43     void build(){
     44         m=n;
     45         memset(head,-1,sizeof(head));
     46         for(int i=1;i<n;i++){
     47             scanf("%d%d%d",&x,&y,&z);
     48             add(x,y,z),add(y,x,z);
     49         }
     50         dfs(1,0,0);
     51         E=0;
     52         memset(head,-1,sizeof(head));
     53         for(int i=1;i<=m;i++)assert(e[i].size()<=2); 
     54         for(int i=1;i<=m;i++)
     55             for(int j=0;j<e[i].size();j++){
     56                 add(i,e[i][j].fi,e[i][j].se);
     57                 add(e[i][j].fi,i,e[i][j].se);
     58             }
     59     }
     60     void get_sz(int k,int fa){
     61         sz[k]=1;
     62         for(int i=head[k];i!=-1;i=edge[i].nex)
     63             if ((!vis[i>>1])&&(edge[i].to!=fa)){
     64                 get_sz(edge[i].to,k);
     65                 sz[k]+=sz[edge[i].to];
     66             } 
     67     }
     68     void get_rt(int k,int fa,int s){
     69         for(int i=head[k];i!=-1;i=edge[i].nex)
     70             if ((!vis[i>>1])&&(edge[i].to!=fa)){
     71                 get_rt(edge[i].to,k,s);
     72                 if ((s<=3*sz[edge[i].to]+1)&&(3*sz[edge[i].to]<=(s+1<<1)))rt=(i>>1);
     73             }
     74     }
     75     void get_v(vi &v,int k,int fa,ll s){
     76         if (k<=n){
     77             val[k]=s+dep[k];
     78             v.push_back(k);
     79         }
     80         for(int i=head[k];i!=-1;i=edge[i].nex)
     81             if ((!vis[i>>1])&&(edge[i].to!=fa))get_v(v,edge[i].to,k,s+edge[i].len);
     82     }
     83     void divide(int k){
     84         get_sz(k,0);
     85         if (sz[k]==1)return;
     86         get_rt(k,0,sz[k]);
     87         k=rt,vis[k]=1;
     88         vx.clear(),vy.clear();
     89         get_v(vx,edge[k<<1].to,0,0);
     90         get_v(vy,edge[(k<<1)|1].to,0,0);
     91         ans=max(ans,calc(vx,vy)+edge[k<<1].len);
     92         divide(edge[k<<1].to);
     93         divide(edge[(k<<1)|1].to);
     94     }
     95 };
     96 namespace T2{
     97     int E,x,y,z,head[N],dfn[N],sh[N],f[N][20],st[N];
     98     ll ans,dep[N],mx[N][2];
     99     vi v0,v,e[N];
    100     Edge edge[N<<1];
    101     bool cmp(int x,int y){
    102         return dfn[x]<dfn[y];
    103     }
    104     void add(int x,int y,int z){
    105         edge[E]=Edge{head[x],y,z};
    106         head[x]=E++;
    107     }
    108     int lca(int x,int y){
    109         if (sh[x]<sh[y])swap(x,y);
    110         for(int i=19;i>=0;i--)
    111             if (sh[f[x][i]]>=sh[y])x=f[x][i];
    112         if (x==y)return x;
    113         for(int i=19;i>=0;i--)
    114             if (f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    115         return f[x][0];
    116     }
    117     void dfs(int k,int fa,int s1,ll s2){
    118         dfn[k]=++dfn[0],sh[k]=s1,dep[k]=s2;
    119         f[k][0]=fa;
    120         for(int i=1;i<20;i++)f[k][i]=f[f[k][i-1]][i-1];
    121         for(int i=head[k];i!=-1;i=edge[i].nex)
    122             if (edge[i].to!=fa)dfs(edge[i].to,k,s1+1,s2+edge[i].len);
    123     }
    124     void build(){
    125         memset(head,-1,sizeof(head));
    126         for(int i=1;i<n;i++){
    127             scanf("%d%d%d",&x,&y,&z);
    128             add(x,y,z),add(y,x,z);
    129         }
    130         dfs(1,1,0,0);
    131     }
    132     void build(vi v0){
    133         bool flag=0;
    134         for(int i=0;i<v0.size();i++)
    135             if (v0[i]==1)flag=1;
    136         if (!flag){
    137             v0.push_back(1);
    138             v.push_back(1);
    139         }
    140         sort(v0.begin(),v0.end(),cmp);
    141         st[0]=st[1]=1;
    142         for(int i=1;i<v0.size();i++){
    143             int k=lca(v0[i],st[st[0]]);
    144             while ((st[0]>1)&&(dfn[st[st[0]-1]]>=dfn[k])){
    145                 e[st[st[0]-1]].push_back(st[st[0]]);
    146                 st[0]--;
    147             }
    148             if (k!=st[st[0]]){
    149                 v.push_back(k);
    150                 e[k].push_back(st[st[0]]);
    151                 st[st[0]]=k;
    152             }
    153             st[++st[0]]=v0[i];
    154         }
    155         while (st[0]>1){
    156             e[st[st[0]-1]].push_back(st[st[0]]);
    157             st[0]--;
    158         }
    159     }
    160     void dfs(int k){
    161         for(int i=0;i<e[k].size();i++){
    162             dfs(e[k][i]);
    163             ans=max(ans,max(mx[k][0]+mx[e[k][i]][1],mx[k][1]+mx[e[k][i]][0])-(dep[k]<<1));
    164             mx[k][0]=max(mx[k][0],mx[e[k][i]][0]);
    165             mx[k][1]=max(mx[k][1],mx[e[k][i]][1]); 
    166         }
    167     }
    168     ll calc(vi vx,vi vy){
    169         ans=-1e18,v0.clear();
    170         for(int i=0;i<vx.size();i++)v0.push_back(vx[i]);
    171         for(int i=0;i<vy.size();i++)v0.push_back(vy[i]);
    172         v=v0,build(v0);
    173         for(int i=0;i<v.size();i++)mx[v[i]][0]=mx[v[i]][1]=-1e18;
    174         for(int i=0;i<vx.size();i++)mx[vx[i]][0]=val[vx[i]];
    175         for(int i=0;i<vy.size();i++)mx[vy[i]][1]=val[vy[i]];
    176         dfs(1);
    177         for(int i=0;i<v.size();i++)e[v[i]].clear();
    178         return ans;
    179     }
    180 };
    181 ll calc(vi x,vi y){
    182     return T2::calc(x,y);
    183 }
    184 int main(){
    185     scanf("%d",&n);
    186     T1::build();
    187     T2::build();
    188     for(int i=1;i<=n;i++)ans=max(ans,(T1::dep[i]-T2::dep[i])<<1);
    189     T1::divide(1);
    190     printf("%lld
    ",(ans>>1));
    191     return 0;
    192 }
    View Code

    实际上,点分治也是可以做的

    相比于边分治,点分治即要维护多棵子树中选两个不同的子树(而不是两个),那么仍暴力维护复杂度即退化为$o(n^{2}log n)$,显然无法通过

    考虑不断选择两棵最小的子树,并对这两棵子树内的点建虚树后求答案,求完后将两棵子树合并为一棵子树(注意这棵子树之后也可以参与合并)

    关于复杂度,理性分析可以得到仍是$o(nlog^{2}n)$的(不优化虚树),感性理解一下即考虑合并过程的逆过程,不难发现与边分治等价,因此与边分治复杂度相同

  • 相关阅读:
    Spring中使用Log4j记录日志
    Spring MVC异常处理实例
    Spring MVC静态资源实例
    Spring MVC页面重定向实例
    Spring MVC表单实例
    Eclipse4.6安装Tomcat插件时报错:Unable to read repository at http://tomcatplugin.sf.net/update/content.xml. Received fatal alert: handshake_failure
    Graphviz--图形绘制工具
    使用Maven+Nexus+Jenkins+Svn+Tomcat+Sonar搭建持续集成环境
    MySQL在并发场景下的问题及解决思路
    MIT KIT OpenID Connect Demo Client
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15315968.html
Copyright © 2011-2022 走看看