bzoj 2238 Mst——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238
一条非树边可以对一条链的树边产生影响。注意是边,所以把边下放到点上,只要跳 top 时不赋 lca 就行。
然后WA*3。看看题解才知道有一开始图就不连通的情况!自己还是太嫩了……
只有单点查询很方便用标记永久化。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=5e4+5,M=1e5+5; int n,m,q,hd[N],xnt,to[N<<1],nxt[N<<1],fa[N],ans; int tim,dfn[N],siz[N],dep[N],son[N],top[N]; int tot,ls[N<<1],rs[N<<1],mn[N<<1]; bool used[M],flag; struct Ed{ int x,y,w,bh; Ed(int a=0,int b=0,int c=0,int d=0):x(a),y(b),w(c),bh(d) {} bool operator< (const Ed &b)const {return w<b.w;} }ed[M]; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return fx?ret:-ret; } bool cmp(Ed u,Ed v){return u.bh<v.bh;} int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);} void add(int x,int y) { to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt; to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt; } void dfs(int cr) { dep[cr]=dep[fa[cr]]+1; siz[cr]=1; for(int i=hd[cr],v;i;i=nxt[i]) if((v=to[i])!=fa[cr]) { fa[v]=cr; dfs(v); siz[cr]+=siz[v]; siz[v]>siz[son[cr]]?son[cr]=v:0; } } void dfsx(int cr) { dfn[cr]=++tim; if(son[cr])top[son[cr]]=top[cr],dfsx(son[cr]); for(int i=hd[cr],v;i;i=nxt[i]) if((v=to[i])!=fa[cr]&&v!=son[cr]) top[v]=v,dfsx(v); } void build(int l,int r,int cr) { mn[cr]=M; if(l==r)return; int mid=l+r>>1; ls[cr]=++tot; build(l,mid,ls[cr]); rs[cr]=++tot; build(mid+1,r,rs[cr]); } void mdfy(int l,int r,int cr,int L,int R,int k) { if(l>=L&&r<=R){mn[cr]=min(mn[cr],k);return;} int mid=l+r>>1; if(L<=mid)mdfy(l,mid,ls[cr],L,R,k); if(mid<R)mdfy(mid+1,r,rs[cr],L,R,k); } void mdfy(int x,int y,int w) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); mdfy(1,n,1,dfn[top[x]],dfn[x],w); x=fa[top[x]]; } if(x==y)return;// if(dep[x]<dep[y])swap(x,y); mdfy(1,n,1,dfn[son[y]],dfn[x],w);//son for no lca } int query(int l,int r,int cr,int p) { if(l==r)return mn[cr]; int mid=l+r>>1; if(p<=mid)return min(query(l,mid,ls[cr],p),mn[cr]); else return min(query(mid+1,r,rs[cr],p),mn[cr]); } int main() { n=rdn();m=rdn(); for(int i=1,u,v,z;i<=m;i++) { u=rdn(); v=rdn(); z=rdn(); ed[i]=Ed(u,v,z,i); } for(int i=1;i<=n;i++)fa[i]=i; sort(ed+1,ed+m+1); for(int i=1,u,v;i<=m;i++) if((u=find(ed[i].x))!=(v=find(ed[i].y))) { used[ed[i].bh]=1; fa[u]=v; add(ed[i].x,ed[i].y); ans+=ed[i].w; } int d=find(1); for(int i=2;i<=n;i++)if(find(i)!=d){flag=1;break;} if(!flag) { sort(ed+1,ed+m+1,cmp); fa[1]=0; dfs(1); top[1]=1; dfsx(1); tot=1; build(1,n,1); for(int i=1;i<=m;i++) if(!used[i]) mdfy(ed[i].x,ed[i].y,ed[i].w); } q=rdn(); for(int i=1,d;i<=q;i++) { d=rdn(); if(flag){puts("Not connected");continue;} if(!used[d])printf("%d\n",ans); else { int k=query(1,n,1,max(dfn[ed[d].x],dfn[ed[d].y]));//ed[d]! if(k==M)puts("Not connected"); else printf("%d\n",ans-ed[d].w+k);//ed[d]! } } return 0; }