BZOJ2238
题意:给一张图,多次询问删去其中一条边后mst大小,删去后图不连通输出Not connected,询问之间相互独立
分析:
一个显然的结论是一条非MST上的边会和MST形成一个环,这个环上任意断开一条边都可以形成一棵生成树
所以我们只需要对于所有非树边,把它能够更新的所有边都打上标记
询问一条边上的所有标记中的最小值即可
注意如果原图不连通,直接全部输出Not connected
Code:
#include<bits/stdc++.h>
#define INF 1e9
#define ls tr[k].l
#define rs tr[k].r
#define mid ((ls+rs)>>1)
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=100005;
struct E{int x,y,z;int num;}e[N<<1];
int n,m,q,u,v,w;
int vis[N<<1],head[N<<1],nxt[N<<1],c[N<<1],tot=0;
int fa[N],pt[N],dep[N],siz[N],hson[N];
int top[N],dfn[N],id[N],sign=0;
int ff[N],a[N];
int ise[N];
int mst=0;
namespace segtree{
struct segtree{int l,r,mx,tag;}tr[N<<2];
inline void pushup(int k) {tr[k].mx=min(tr[k<<1].mx,tr[k<<1|1].mx);}
inline void pushmx(int k,int v){tr[k].mx=min(tr[k].mx,v);tr[k].tag=min(tr[k].tag,v);}
inline void pushdown(int k){
if(tr[k].tag){
pushmx(k<<1,tr[k].tag);
pushmx(k<<1|1,tr[k].tag);
tr[k].tag=INF;
}
}
void build(int k,int l,int r){
ls=l,rs=r,tr[k].tag=INF;
if(l==r) {tr[k].mx=INF;return;}
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
pushup(k);
}
void modify(int k,int ql,int qr,int v){
if(ql>rs || qr<ls) return;
if(ql<=ls && rs<=qr) {pushmx(k,v);return;}
pushdown(k);
if(qr<=mid) modify(k<<1,ql,qr,v);
else if(ql>mid) modify(k<<1|1,ql,qr,v);
else modify(k<<1,ql,mid,v),modify(k<<1|1,mid+1,qr,v);
pushup(k);
}
int query(int k,int ql,int qr){
if(ql>rs || qr<ls) return INF;
if(ql<=ls && rs<=qr) return tr[k].mx;
pushdown(k);
if(qr<=mid) return query(k<<1,ql,qr);
else if(ql>mid) return query(k<<1|1,ql,qr);
else return min(query(k<<1,ql,mid),query(k<<1|1,mid+1,qr));
pushup(k);
}
}
namespace tree{
using namespace segtree;
int get(int v){return v==ff[v]?v:ff[v]=get(ff[v]);}
inline void add(int x,int y,int z) {vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
inline bool cmp(E a,E b) {return a.z<b.z;}
inline bool cmp1(E a,E b) {return a.num<b.num;}
inline int kruscal(){
int tott=0;
for(int i=1;i<=n;i++) ff[i]=i;
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
int xx=get(e[i].x),yy=get(e[i].y);
if(xx==yy) continue;ise[e[i].num]=1;
++tott;ff[xx]=yy;add(e[i].x,e[i].y,e[i].z);add(e[i].y,e[i].x,e[i].z);
mst+=e[i].z;
}
return tott;
}
void dfs1(int v){
pt[v]=siz[v]=1;int maxn=0;
for(int i=head[v];i;i=nxt[i]){
int y=vis[i];
if(pt[y]) continue;
dep[y]=dep[v]+1; fa[y]=v; a[y]=c[i];
dfs1(y);
siz[v]+=siz[y];
if(siz[y]>maxn) maxn=siz[y],hson[v]=y;
}
}
void dfs2(int v){
dfn[v]=++sign;id[sign]=v;
if(hson[v]) top[hson[v]]=top[v],dfs2(hson[v]);
for(int i=head[v];i;i=nxt[i]) if(!top[vis[i]]) top[vis[i]]=vis[i],dfs2(vis[i]);
}
inline void change(int x,int y,int z){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modify(1,dfn[top[x]],dfn[x],z);x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
modify(1,dfn[y]+1,dfn[x],z);
}
inline int ask(int x,int y){
int ret=INF;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ret=min(ret,query(1,dfn[top[x]],dfn[x]));x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
ret=min(ret,query(1,dfn[y]+1,dfn[x]));
return ret;
}
inline void work(){
int flag=1;
n=read(),m=read();
for(int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].z=read(),e[i].num=i;
if(kruscal()<n-1) flag=0;
dfs1(1);top[1]=1;dfs2(1);build(1,1,n);
sort(e+1,e+m+1,cmp1);
for(int i=1;i<=m;i++) if(!ise[i]) change(e[i].x,e[i].y,e[i].z);
q=read();
if(!flag){
while(q--) puts("Not connected");
}
else while(q--){
u=read();
if(!ise[u]) cout<<mst<<'\n';
else{
int ans=mst-e[u].z;
int aaa=ask(e[u].x,e[u].y);
if(aaa==INF) {puts("Not connected");continue;}
ans+=aaa;
cout<<ans<<'\n';
}
}
}
}
int main(){
tree::work();
return 0;
}