BZOJ2238 Mst[最小生成树+树剖+线段树]

跑一遍mst。对于非mst上的边,显然删掉不影响。

如果删边在树上,相当于这时剩下两个连通块。可以证明要重新构成mst只需要再加一条连接两个连通块的最小边,不会证,yy一下,因为原来连通块连的边权和已经最小化了,就不要动,如果换用两条以上的边,肯定不会更优。

所以问题就是断掉树边,找最小联通边。可以LCT。`````

这种一颗树断成两截找联通边的题有一个常用思路,要使得联通,必须得有非树边两端点形成的链过这个断边。换句话说,一条非树边两点形成的树上链可以在树断掉后成为联通边当且仅当他经过的边断掉。

这个思路应该在先前这个poj题「闇の連鎖」中出现过,很容易证。

那么只要看经过这个断边的所有非树边中最小的是哪个,用他来联通,总体来看,就是把每条非树边路径上用自己的代价更新一波最小值。

用线段树打标记维护,最后查询的时候直接查单点最小值计算答案即可。

注意判无解。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 #define dbg(x) cerr << #x << " = " << x <<endl
  7 using namespace std;
  8 typedef long long ll;
  9 typedef double db;
 10 typedef pair<int,int> pii;
 11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
 12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
 13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
 14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
 15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
 16 template<typename T>inline T read(T&x){
 17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
 18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
 19 }
 20 const int N=1e5+7,INF=0x3f3f3f3f;
 21 struct thxorz{int to,nxt,w;}G[N];
 22 int Head[N],tot,used[N];
 23 int n,m,q;
 24 inline void Addedge(int x,int y,int z){
 25     G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot,G[tot].w=z;
 26     G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot,G[tot].w=z;
 27 }
 28 struct stothx{
 29     int u,v,w,id;
 30     inline bool operator <(const stothx&x)const{return w<x.w;}
 31 }E[N],_E[N];
 32 int anc[N],ans;
 33 int get_anc(int x){return x==anc[x]?x:anc[x]=get_anc(anc[x]);}
 34 int fa[N],topfa[N],son[N],cnt[N],d[N],st[N],tim;
 35 #define y G[j].to
 36 void dfs1(int x,int f){
 37     fa[x]=f,d[x]=d[f]+1,cnt[x]=1;int tmp=-1;
 38     for(register int j=Head[x];j;j=G[j].nxt)if(y^f)dfs1(y,x),cnt[x]+=cnt[y],MAX(tmp,cnt[y])&&(son[x]=y);
 39 }
 40 void dfs2(int x,int topf){
 41     topfa[x]=topf,st[x]=tim++;if(!son[x])return;dfs2(son[x],topf);
 42     for(register int j=Head[x];j;j=G[j].nxt)if(y^fa[x]&&y^son[x])dfs2(y,y);
 43 }
 44 #undef y
 45 #define lc i<<1
 46 #define rc i<<1|1
 47 int minv[N<<1],mtag[N<<1];
 48 inline void pushup(int i){minv[i]=_min(minv[lc],minv[rc]);}
 49 inline void pushdown(int i){
 50     if(mtag[i]<INF)
 51         MIN(minv[lc],mtag[i]),MIN(minv[rc],mtag[i]),MIN(mtag[lc],mtag[i]),MIN(mtag[rc],mtag[i]),mtag[i]=INF;
 52 }
 53 void Update(int i,int L,int R,int ql,int qr,int val){//dbg(L),dbg(R),dbg(ql),dbg(qr);
 54     if(ql<=L&&qr>=R){MIN(minv[i],val),MIN(mtag[i],val);return;}
 55     int mid=L+R>>1;pushdown(i);
 56     if(ql<=mid)Update(lc,L,mid,ql,qr,val);
 57     if(qr>mid)Update(rc,mid+1,R,ql,qr,val);
 58     pushup(i);
 59 }
 60 int Query_min(int i,int L,int R,int x){
 61     if(L==R)return minv[i];
 62     int mid=L+R>>1;pushdown(i);
 63     return x<=mid?Query_min(lc,L,mid,x):Query_min(rc,mid+1,R,x);
 64 }
 65 inline void Tree_update(int x,int y,int z){
 66     while(topfa[x]^topfa[y]){
 67         if(d[topfa[x]]<d[topfa[y]])x^=y^=x^=y;
 68         Update(1,1,n-1,st[topfa[x]],st[x],z),x=fa[topfa[x]];
 69     }
 70     if(d[x]>d[y])x^=y^=x^=y;
 71     if(x^y)Update(1,1,n-1,st[x]+1,st[y],z);
 72 }
 73 inline void mst(){
 74     sort(E+1,E+m+1);int res=0;
 75     for(register int i=1;i<=n;++i)anc[i]=i;
 76     for(register int i=1;i<=m;++i)
 77         if(get_anc(E[i].u)^get_anc(E[i].v)){
 78             anc[get_anc(E[i].v)]=get_anc(E[i].u);
 79             used[E[i].id]=1,ans+=E[i].w;++res;
 80             Addedge(E[i].u,E[i].v,E[i].w);
 81         }
 82     if(res<n-1){while(q--)puts("Not connected");exit(0);}
 83     dfs1(1,0),dfs2(1,1);
 84     memset(mtag,0x3f,sizeof mtag),memset(minv,0x3f,sizeof minv);
 85     for(register int i=1;i<=m;++i){
 86         if(used[i])used[i]=d[_E[i].u]<d[_E[i].v]?_E[i].v:_E[i].u;
 87         else Tree_update(_E[i].u,_E[i].v,_E[i].w);
 88     }
 89 }
 90 int id;
 91 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
 92     read(n);read(m);
 93     for(register int i=1;i<=m;++i)_E[i].u=read(E[i].u),_E[i].v=read(E[i].v),_E[i].w=read(E[i].w),E[i].id=i;
 94     read(q);mst();
 95     while(q--){
 96         read(id);if(!used[id]){printf("%d\n",ans);continue;}
 97         int tmp=Query_min(1,1,n-1,st[used[id]]);
 98         if(tmp<INF)printf("%d\n",ans-_E[id].w+tmp);
 99         else puts("Not connected");
100     }
101     return 0;
102 }
View Code

反思:注意这个提到的常用思路,即化非树边为树上链的边覆盖问题。

转载于:https://www.cnblogs.com/saigyouji-yuyuko/p/11588941.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值