zoukankan      html  css  js  c++  java
  • [luogu5344]逛森林

    由于没有删边操作,可以先建出整棵森林,之后再用并查集判断是否连通,若连通必然与最后的森林相同

    但如果用树链剖分+线段树的形式来优化建图,更具体如下:

    建立两颗线段树,左边从儿子连向父亲,右边从父亲连向儿子,再将右边线段树上的连向左边对应的点,那么复杂度为$o(mlog^{3}n)$(前两个$log$为边数,最后一个$log$是求最短路)

    考虑倍增去建立,由于可以重复建立,用ST表的方法去做即可,这样每一条链只对应于至多4个点(上下各两个),即边数为$o(m)$

    还有一个问题,就是如何建立倍增所新增的点之间的边,这个并没有线段树的结构那么简单,如果暴力来说,即对于每一个点,向所有包含其的倍增的链连边,这样的边数是$o(n^{2})$的

    下面考虑这样一种方式:对于每一个长度不小于2的倍增的链(即不为一个点),向组成其的两条链连边即可,不难发现此时对于一个点以及包含其的倍增的链,这条链的两部分中总(恰好)有一个部分包含该点,由此归纳即可证明这样的连边与前面暴力等价,这一部分的边数降为$o(nlog n)$

    总复杂度为$o(mlog n+nlog^{2}n)$,可以通过

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 50005
      4 #define M 1000005
      5 #define oo 0x3f3f3f3f
      6 #define pii pair<int,int>
      7 #define mp make_pair
      8 struct Edge{
      9     int nex,to,len;
     10 }edge[(N<<6)+(M<<4)];
     11 struct op{
     12     int p,x1,y1,x2,y2,w;
     13 }a[M];
     14 vector<int>vl,vr,v[N];
     15 priority_queue<pii >q;
     16 int V,E,n,m,s,fa[N],dep[N],f[N][16],head[N<<5],vis[N<<5],d[N<<5];
     17 int find(int k){
     18     if (k==fa[k])return k;
     19     return fa[k]=find(fa[k]);
     20 }
     21 bool check(int x,int y){//1表示不相连 
     22     return find(x)!=find(y);
     23 }
     24 void merge(int x,int y){
     25     fa[find(x)]=find(y);
     26 }
     27 int id(int k,int x){
     28     return (k-1)*16+x+1;
     29 }
     30 int lca(int x,int y){
     31     if (dep[x]<dep[y])swap(x,y);
     32     for(int i=15;i>=0;i--)
     33         if (dep[f[x][i]]>=dep[y])x=f[x][i];
     34     if (x==y)return x;
     35     for(int i=15;i>=0;i--)
     36         if (f[x][i]!=f[y][i]){
     37             x=f[x][i];
     38             y=f[y][i];
     39         }
     40     return f[x][0];
     41 }
     42 void div(int x,int y,vector<int>&v){
     43     int p=15;
     44     while ((1<<p)>dep[x]-dep[y]+1)p--;
     45     v.push_back(id(x,p));
     46     if (dep[x]-dep[y]+1==(1<<p))return;
     47     int d=dep[y]+(1<<p)-1;
     48     for(int i=15;i>=0;i--)
     49         if (dep[f[x][i]]>=d)x=f[x][i];
     50     v.push_back(id(x,p));
     51 }
     52 void dfs(int k,int fa,int s){
     53     dep[k]=s;
     54     f[k][0]=fa;
     55     for(int i=1;i<=15;i++)f[k][i]=f[f[k][i-1]][i-1];
     56     for(int i=0;i<v[k].size();i++)
     57         if (v[k][i]!=fa)dfs(v[k][i],k,s+1);
     58 }
     59 void add(int x,int y,int z){
     60     edge[E].nex=head[x];
     61     edge[E].to=y;
     62     edge[E].len=z;
     63     head[x]=E++;
     64 }
     65 void dij(int s){
     66     memset(d,oo,sizeof(d));
     67     d[s]=0;
     68     q.push(mp(0,s));
     69     while (!q.empty()){
     70         int k=q.top().second;
     71         q.pop();
     72         if (vis[k])continue;
     73         vis[k]=1;
     74         for(int i=head[k];i!=-1;i=edge[i].nex)
     75             if (d[edge[i].to]>d[k]+edge[i].len){
     76                 d[edge[i].to]=d[k]+edge[i].len;
     77                 q.push(mp(-d[edge[i].to],edge[i].to));
     78             }
     79     }
     80 }
     81 int main(){
     82     scanf("%d%d%d",&n,&m,&s);
     83     for(int i=1;i<=n;i++)fa[i]=i;
     84     for(int i=1;i<=m;i++){
     85         scanf("%d%d%d",&a[i].p,&a[i].x1,&a[i].y1);
     86         if (a[i].p==1)scanf("%d%d",&a[i].x2,&a[i].y2);
     87         else{
     88             if (check(a[i].x1,a[i].y1)){
     89                 merge(a[i].x1,a[i].y1);
     90                 v[a[i].x1].push_back(a[i].y1);
     91                 v[a[i].y1].push_back(a[i].x1);
     92             }
     93         }
     94         scanf("%d",&a[i].w);
     95     }
     96     for(int i=1;i<=n;i++)
     97         if (!f[i][0])dfs(i,i,0);
     98     for(int i=1;i<=n;i++)fa[i]=i;
     99     memset(head,-1,sizeof(head));
    100     V=id(n,15);
    101     for(int i=1;i<=n;i++){
    102         add(id(i,0),id(i,0)+V,0);
    103         add(id(i,0)+V,id(i,0),0);
    104     }
    105     for(int i=1;i<=n;i++)
    106         for(int j=1;j<=15;j++){
    107             add(id(i,j-1),id(i,j),0);
    108             add(id(f[i][j-1],j-1),id(i,j),0);
    109             add(id(i,j)+V,id(i,j-1)+V,0);
    110             add(id(i,j)+V,id(f[i][j-1],j-1)+V,0);
    111         }
    112     for(int i=1;i<=m;i++){
    113         if (a[i].p==2){
    114             if (check(a[i].x1,a[i].y1)){
    115                 merge(a[i].x1,a[i].y1);
    116                 add(id(a[i].x1,0),id(a[i].y1,0)+V,a[i].w);
    117                 add(id(a[i].y1,0),id(a[i].x1,0)+V,a[i].w);
    118             }
    119         }
    120         else{
    121             if ((check(a[i].x1,a[i].y1))||(check(a[i].x2,a[i].y2)))continue;
    122             vl.clear(),vr.clear();
    123             int z=lca(a[i].x1,a[i].y1);
    124             div(a[i].x1,z,vl);
    125             div(a[i].y1,z,vl);
    126             z=lca(a[i].x2,a[i].y2);
    127             div(a[i].x2,z,vr);
    128             div(a[i].y2,z,vr);
    129             for(int x=0;x<vl.size();x++)
    130                 for(int y=0;y<vr.size();y++)add(vl[x],vr[y]+V,a[i].w);
    131         }
    132     }
    133     dij(id(s,0));
    134     for(int i=1;i<=n;i++){
    135         int ans=d[id(i,0)+V];
    136         if (ans==oo)ans=-1;
    137         printf("%d ",ans);
    138     }
    139 } 
    View Code
  • 相关阅读:
    【Redis破障之路】四:Jedis基本使用
    【JVM进阶之路】十二:字节码指令
    Java学习之Spring MVC路由映射
    Java安全之FastJson JdbcRowSetImpl 链分析
    Allatori混淆动态调试分析
    Java工具开发手记
    Java安全之JBoss反序列化漏洞分析
    docker 应用篇————swarm[二十]
    docker 应用篇————docker-compose[十九]
    docker 应用篇————docker 自定义网络[十八]
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14425748.html
Copyright © 2011-2022 走看看