[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
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14425748.html