1. 程式人生 > >bzoj 2238 Mst —— 樹剖+mn標記永久化

bzoj 2238 Mst —— 樹剖+mn標記永久化

date nec urn || oid struct 影響 %d 路徑

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2238

看了半天...

首先,想要知道每條邊刪除之後的替代中最小的那個;

反過來看,每條不在 MST 上的邊如果加入,會對一條路徑產成影響,具體來說,就是這條路徑上的所有邊在被刪除後,可以考慮用這條非 MST 邊替代;

於是就可以用樹剖,對每條非 MST 邊,維護一下路徑上的最小值;

於是寫了一下,但WA了,仔細看看,mn 和 lzy 更新的地方似乎有點不太對,比如沒有更新 mn 也可以更新 lzy 什麽的...(因為 mn 還被左右兒子更新,所以可能比 lzy 更小...)

反正是取min,標記永久化很方便呢(幹脆沒有 lzy ),於是又跟 Narh 學了一下 mn 標記永久化的寫法。

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
#define ls (x<<1)
#define rs (x<<1|1)
using namespace std;
int const xn=50005,xm=1e5+5,inf=0x3f3f3f3f;
int n,m,hd[xn],ct,nxt[xn<<1],to[xn<<1],dep[xn],siz[xn],son[xn],dfn[xn],top[xn],fa[xn],tim;
int mn[xn<<2],lzy[xn<<2],ans; bool use[xm],fl; struct N{int u,v,w,id;}e[xm]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<0||ch>9){if(ch==-)f=0; ch=getchar();} while(ch>=0&&ch<=9)ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar(); return f?ret:-ret; }
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;} bool cmp(N x,N y){return x.w<y.w;} bool cmp2(N x,N y){return x.id<y.id;} int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void dfs(int x) { dep[x]=dep[fa[x]]+1; siz[x]=1; for(int i=hd[x],u;i;i=nxt[i]) { if((u=to[i])==fa[x])continue; fa[u]=x; dfs(u); siz[x]+=siz[u]; if(siz[u]>siz[son[x]])son[x]=u; } } void dfs2(int x) { dfn[x]=++tim; if(son[x])top[son[x]]=top[x],dfs2(son[x]); for(int i=hd[x],u;i;i=nxt[i]) { if((u=to[i])==fa[x]||u==son[x])continue; top[u]=u; dfs2(u); } } void pushdown(int x) { if(lzy[x]==-1)return; if(lzy[x]<mn[ls])mn[ls]=lzy[x],lzy[ls]=lzy[x]; if(lzy[x]<mn[rs])mn[rs]=lzy[x],lzy[rs]=lzy[x]; lzy[x]=-1; } void update(int x,int l,int r,int L,int R,int d) { // if(l>=L&&r<=R){if(d<mn[x])mn[x]=d,lzy[x]=d; return;} // pushdown(x); if(l>=L&&r<=R){mn[x]=min(mn[x],d); return;} // mn[x]=min(mn[x],d); if(mid>=L)update(ls,l,mid,L,R,d); if(mid<R)update(rs,mid+1,r,L,R,d); // mn[x]=min(mn[ls],mn[rs]); } void change(int x,int y,int d) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); update(1,1,n,dfn[top[x]],dfn[x],d); x=fa[top[x]]; } if(x==y)return; if(dep[x]<dep[y])swap(x,y); update(1,1,n,dfn[y]+1,dfn[x],d); } int query(int x,int l,int r,int pos) { if(l==r)return mn[x]; // pushdown(x); // if(pos<=mid)return query(ls,l,mid,pos); // else return query(rs,mid+1,r,pos); if(pos<=mid)return min(mn[x],query(ls,l,mid,pos)); else return min(mn[x],query(rs,mid+1,r,pos)); } int main() { n=rd(); m=rd(); for(int i=1,x,y,z;i<=m;i++)e[i].u=rd(),e[i].v=rd(),e[i].w=rd(),e[i].id=i; sort(e+1,e+m+1,cmp); for(int i=1;i<=n;i++)fa[i]=i; int cnt=0; for(int i=1;i<=m;i++) { int x=find(e[i].u),y=find(e[i].v); if(x==y)continue; add(e[i].u,e[i].v); add(e[i].v,e[i].u); ans+=e[i].w; fa[x]=y; cnt++; use[e[i].id]=1;//id if(cnt==n-1)break; } if(cnt<n-1)fl=1; if(!fl)//省時 { fa[1]=0; dfs(1); top[1]=1; dfs2(1); memset(mn,0x3f,sizeof mn); memset(lzy,-1,sizeof lzy); sort(e+1,e+m+1,cmp2); for(int i=1;i<=m;i++) { if(use[i])continue; change(e[i].u,e[i].v,e[i].w); } } int q=rd(); for(int i=1,x;i<=q;i++) { x=rd(); if(fl){puts("Not connected"); continue;} if(!use[x]){printf("%d\n",ans); continue;} int k=query(1,1,n,max(dfn[e[x].u],dfn[e[x].v])); if(k==inf)puts("Not connected"); else printf("%d\n",ans-e[x].w+k); } return 0; }

bzoj 2238 Mst —— 樹剖+mn標記永久化