NOI2014 魔法森林 LCT维护MST
2017-12-02 10:21
281 查看
BZOJ3669 题面
从更简单的情况入手,如果边权只有a没有b应该怎么处理?这时候问题就是找一条从1到N的路径,使得最长的边尽量短。根据最小生成树的性质,这样的边一定在最小生成树上。
如果a固定,得到的解法是一样的。那么可以分别讨论每一个a,对于权值不大于a的边对b做一次最小生成树。暴力做会超时。考虑到随着a的变大,可用的边也逐渐增多,那么只要在加边的同时更新最小生成树就可以了。这个操作可以用LCT处理。
从更简单的情况入手,如果边权只有a没有b应该怎么处理?这时候问题就是找一条从1到N的路径,使得最长的边尽量短。根据最小生成树的性质,这样的边一定在最小生成树上。
如果a固定,得到的解法是一样的。那么可以分别讨论每一个a,对于权值不大于a的边对b做一次最小生成树。暴力做会超时。考虑到随着a的变大,可用的边也逐渐增多,那么只要在加边的同时更新最小生成树就可以了。这个操作可以用LCT处理。
#include<stdio.h> #include<algorithm> #define MAXN 150005 #define MAXM 200005 using namespace std; int N,M,Ans=1e9; struct node{int st,en,va,vb;}edge[MAXM]; bool operator<(node x,node y) { if(x.va==y.va)return x.vb<y.vb; return x.va<y.va; } int ls[MAXN],rs[MAXN],fa[MAXN],rev[MAXN],val[MAXN]; int Max[MAXN],id[MAXN]; bool isrt(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;} void Update(int p) { if(Max[ls[p]]>Max[rs[p]])Max[p]=Max[ls[p]],id[p]=id[ls[p]]; else Max[p]=Max[rs[p]],id[p]=id[rs[p]]; if(Max[p]<val[p])Max[p]=val[p],id[p]=p; } void Putdown(int p) { if(rev[p]==0)return; rev[ls[p]]^=1;rev[rs[p]]^=1;rev[p]=0; swap(ls[p],rs[p]); } void Zig(int x) { int y=fa[x],z=fa[y]; if(!isrt(y)) { if(ls[z]==y)ls[z]=x; else rs[z]=x; } fa[x]=z;fa[y]=x;fa[rs[x]]=y; ls[y]=rs[x];rs[x]=y; Update(y);Update(x); } void Zag(int x) { int y=fa[x],z=fa[y]; if(!isrt(y)) { if(ls[z]==y)ls[z]=x; else rs[z]=x; } fa[x]=z;fa[y]=x;fa[ls[x]]=y; rs[y]=ls[x];ls[x]=y; Update(y);Update(x); } int s[MAXN],Top; void Splay(int x) { int i,y,z; s[++Top]=x; for(i=x;!isrt(i);i=fa[i])s[++Top]=fa[i]; while(Top)Putdown(s[Top--]); while(!isrt(x)) { y=fa[x];z=fa[y]; if(isrt(y)) { if(ls[y]==x)Zig(x); e850 else Zag(x); } else { if(ls[z]==y) { if(ls[y]==x)Zig(y),Zig(x); else Zag(x),Zig(x); } else { if(rs[y]==x)Zag(y),Zag(x); else Zig(x),Zag(x); } } } } void Access(int x) { int t=0; while(x) { Splay(x); rs[x]=t;Update(x); t=x;x=fa[x]; } } void SetRt(int x) { Access(x);Splay(x);rev[x]^=1; } void Link(int x,int y) { SetRt(x);fa[x]=y; } void Cut(int x,int y) { SetRt(x); Access(y);Splay(y); ls[y]=fa[x]=0; Update(y); } int FindRt(int x) { Access(x);Splay(x); while(ls[x])x=ls[x]; return x; } int tot,lk[MAXM][2]; void Add(int x,int y,int v) { tot++; lk[tot][0]=x;lk[tot][1]=y; val[tot]=v;id[tot]=tot; Link(x,tot);Link(tot,y); } void Del(int x) { Cut(x,lk[x][0]);Cut(x,lk[x][1]); } int GetMax(int x,int y,int op) { SetRt(x); Access(y);Splay(y); if(op==1)return Max[y]; else return id[y]; } int main() { int i,j; scanf("%d%d",&N,&M); for(i=1;i<=M;i++)scanf("%d%d%d%d",&edge[i].st,&edge[i].en,&edge[i].va,&edge[i].vb); sort(edge+1,edge+M+1); tot=N; for(i=j=1;i<=50000;i++) { while(j<=M&&edge[j].va<=i) { int x,y; if(edge[j].st==edge[j].en){j++;continue;} x=FindRt(edge[j].st); y=FindRt(edge[j].en); if(x!=y)Add(edge[j].st,edge[j].en,edge[j].vb); else { int tmp=GetMax(edge[j].st,edge[j].en,1); if(tmp>edge[j].vb) { tmp=GetMax(edge[j].st,edge[j].en,2); Del(tmp);Add(edge[j].st,edge[j].en,edge[j].vb); } } j++; } if(FindRt(1)!=FindRt(N))continue; Ans=min(Ans,i+GetMax(1,N,1)); } if(Ans==1e9)puts("-1"); else printf("%d\n",Ans); }
相关文章推荐
- 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树
- ☆ [NOI2014] 魔法森林 「LCT动态维护最小生成树」
- BZOJ3669(NOI2014):魔法森林 (LCT维护最小生成树)
- 【LCT维护生成树】BZOJ3669 [Noi2014]魔法森林
- NOI 2014 魔法森林 LCT
- BZOJ 3669 [Noi2014]魔法森林 LCT
- 【BZOJ3669】【NOI2014】魔法森林 LCT
- [BZOJ]3669: [Noi2014]魔法森林 lct
- BZOJ 3669: [Noi2014]魔法森林( LCT )
- LCT——BZOJ3669/Luogu2387 [Noi2014]魔法森林
- UOJ #3(【NOI2014】魔法森林-LCT区间最值)
- NOI 2014 魔法森林 LCT
- [BZOJ3669][Noi2014]魔法森林 && LCT
- [BZOJ3669]NOI2014魔法森林|LCT|最小生成树
- 【BZOJ3669】[Noi2014]魔法森林 LCT
- bzoj 3669: [Noi2014]魔法森林(并查集+LCT)
- NOI2014-魔法森林(LCT)
- [NOI2014魔法森林]LCT
- 3669: [Noi2014]魔法森林 LCT
- BZOJ_P3669&Codevs_P3314 [NOI2014]魔法森林(LCT+Kruskal)