1. 程式人生 > >洛谷 2387 NOI2014魔法森林 LCT

洛谷 2387 NOI2014魔法森林 LCT

wap find image isp ret () std namespace char

技術分享圖片

【題解】

  我們先把邊按照$a$值從小到大排序,並按照這個順序加邊。

  如果當前要加入的邊連接的兩點$u$與$v$已經是連通的,那麽直接加入這條邊就會出現環。這時我們需要刪除這個環中$b$值最大的邊。因此我們需要維護區間最大值,以及最大值的位置。

  如果當前$1$與$n$已經連通,就更新$ans$,當前從$1~n$的代價是$ai+val[querymax(1,n)]$;

  為了方便處理,我們可以把邊開成點,即加邊的時候多開一個表示這條邊的點,在上面記錄邊權等信息。

技術分享圖片
  1 #include<cstdio>
  2 #include<algorithm>
  3
#define N (500010) 4 #define inf (2e9) 5 #define ls (c[u][0]) 6 #define rs (c[u][1]) 7 using namespace std; 8 int n,m,ans; 9 inline int read(){ 10 int k=0,f=1; char c=getchar(); 11 while(c<0||c>9)c==-&&(f=-1),c=getchar(); 12 while(0<=c&&c<=9)k=k*10
+c-0,c=getchar(); 13 return k*f; 14 } 15 struct edge{int u,v,a,b;}e[N]; 16 struct Link_cut_tree{ 17 int top,c[N][2],fa[N],rev[N],q[N],maxpos[N],val[N]; 18 inline void pushdown(int u){ 19 if(rev[u]) rev[ls]^=1,rev[rs]^=1,rev[u]^=1,swap(ls,rs); 20 } 21 inline void pushup(int
u){ 22 maxpos[u]=u; 23 if(val[maxpos[ls]]>val[maxpos[u]]) maxpos[u]=maxpos[ls]; 24 if(val[maxpos[rs]]>val[maxpos[u]]) maxpos[u]=maxpos[rs]; 25 } 26 inline bool isroot(int u){ 27 return c[fa[u]][0]!=u&&c[fa[u]][1]!=u; 28 } 29 inline bool which(int u){ 30 return c[fa[u]][1]==u; 31 } 32 void rotate(int u){ 33 int f=fa[u],gf=fa[f],wh=which(u); 34 if(!isroot(f)) c[gf][which(f)]=u; 35 fa[u]=gf; fa[f]=u; fa[c[u][wh^1]]=f; 36 c[f][wh]=c[u][wh^1]; c[u][wh^1]=f; 37 pushup(f); pushup(u); 38 } 39 void splay(int u){ 40 q[top=1]=u; 41 for(int i=u;!isroot(i);i=fa[i]) q[++top]=fa[i]; 42 for(int i=top;i;i--) pushdown(q[i]); 43 while(!isroot(u)){ 44 if(!isroot(fa[u])) rotate(which(fa[u])==which(u)?fa[u]:u); 45 rotate(u); 46 } 47 pushup(u); 48 } 49 void access(int u){ 50 for(int son=0;u;son=u,u=fa[u]) splay(u),c[u][1]=son,pushup(u); 51 } 52 void makeroot(int u){ 53 access(u); splay(u); rev[u]^=1; 54 } 55 int find(int u){ 56 access(u); splay(u); 57 while(ls) u=ls; 58 return u; 59 } 60 void split(int x,int y){ 61 makeroot(x); access(y); splay(y); 62 } 63 void cut(int x,int y){ 64 split(x,y); 65 c[y][0]=fa[x]=0; 66 pushup(y); 67 } 68 void link(int x,int y){ 69 makeroot(x); fa[x]=y; 70 } 71 int query(int x,int y){ 72 makeroot(x); access(y); splay(y); 73 return maxpos[y]; 74 } 75 }t; 76 bool cmp(edge x,edge y){ 77 return x.a<y.a; 78 } 79 int main(){ 80 ans=inf; 81 n=read(); m=read(); 82 for(int i=1;i<=m;i++) 83 e[i].u=read(),e[i].v=read(),e[i].a=read(),e[i].b=read(); 84 sort(e+1,e+m+1,cmp); 85 for(int i=1;i<=m;i++){ 86 int u=e[i].u,v=e[i].v,a=e[i].a,b=e[i].b; 87 if(t.find(u)==t.find(v)){ 88 int pos=t.query(u,v); 89 if(t.val[pos]>b){ 90 t.cut(pos,e[pos-n].u); 91 t.cut(pos,e[pos-n].v); 92 } 93 else{ 94 if(t.find(1)==t.find(n)) ans=min(ans,a+t.val[t.query(1,n)]); 95 continue; 96 } 97 } 98 t.val[n+i]=b; t.maxpos[n+i]=n+i; 99 t.link(u,n+i); t.link(v,n+i); 100 if(t.find(1)==t.find(n)) ans=min(ans,a+t.val[t.query(1,n)]); 101 } 102 if(ans==inf) puts("-1"); 103 else printf("%d\n",ans); 104 return 0; 105 }
View Code

洛谷 2387 NOI2014魔法森林 LCT