[JZOJ3754]【NOI2014】魔法森林
2017-03-03 22:52
337 查看
题目大意
给定N个点M条边的无向图,每条边有两个权值a与b。求一条1到n的路径使得路径经过边的最大a与最大b的和最小。无法到达输出-1。n<=50000,m<=100000。ai,bi<=50000
分析
看到ai这么小,我们考虑枚举ai然后算最小b。那么从小到大枚举ai,不断加入边,边权为bi。
用LCT维护最小生成树即可。具体的,新加入一条边(x,y),若不在同一联通块就link,在同一联通块看看路径上是否有权值比bi大的,找到最大的,cut,再link(x,y)
若1和n在同一联通块,就算1到n简单路径的大权值,加上ai更新答案。
实现技巧:边权不好维护,我们把边拆成一个点两条边,点权为边权,两条边连向原来两点。
代码
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; #define fo(i,j,k) for(i=j;i<=k;i++) #define fd(i,j,k) for(i=j;i>=k;i--) const int N=200005; struct rec { int x,y,a,b; }b ; int tr [2],tag ,tmax ,tval ,tsiz ,up ,tup ,sta ,st; int dad ,rx,ry; int xx,yy,ans,pp,x,y,z,i,j,n,m,pos; bool cmp(rec a,rec b) { return a.a<b.a; } int get(int x) { if (dad[x]==x) return x; return dad[x]=get(dad[x]); } int pd(int x) { return tr[up[x]][1]==x; } void down(int x) { if (!tag[x]) return; swap(tr[x][0],tr[x][1]); tag[tr[x][0]]^=1; tag[tr[x][1]]^=1; tag[0]=tag[x]=0; } void update(int x) { int ls=tr[x][0],rs=tr[x][1]; tsiz[x]=tsiz[ls]+tsiz[rs]+1; if (tval[tmax[ls]]>tval[tmax[rs]]) tmax[x]=tmax[ls];else tmax[x]=tmax[rs]; if (tval[x]>tval[tmax[x]]) tmax[x]=x; } void rotate(int x) { int y=up[x],z; z=pd(x); up[x]=up[y]; if (up[x]) tr[up[x]][pd(y)]=x; tr[y][z]=tr[x][1-z]; if (tr[y][z]) up[tr[y][z]]=y; tr[x][1-z]=y; up[y]=x; update(y); update(x); if (tup[y]) tup[x]=tup[y]; tup[y]=0; } void remove(int x,int y) { st=1; sta[1]=x; while (x!=y) sta[++st]=(x=up[x]); while (st) down(sta[st--]); } void splay(int x,int y) { remove(x,y); while (up[x]!=y) { if (up[up[x]]!=y) { if (pd(x)==pd(up[x])) rotate(up[x]); else rotate(x); } rotate(x); } } void access(int x) { int last=0,z=x; while (x) { splay(x,0); up[tr[x][1]]=0; if (tr[x][1]) tup[tr[x][1]]=x; tr[x][1]=last; tup[last]=0; if (last) up[last]=x; update(x); last=x; x=tup[x]; } splay(z,0); } void makeroot(int x) { access(x); tag[x]^=1; } void cut(int x,int y) { makeroot(x); access(y); if (tr[y][0]) up[tr[y][0]]=0; tr[y][0]=0; } void link(int x,int y) { makeroot(x); //access(y); splay(x,0); tup[x]=y; } int main() { freopen("3754.in","r",stdin); scanf("%d %d",&n,&m); fo(i,1,m) scanf("%d %d %d %d",&b[i].x,&b[i].y,&b[i].a,&b[i].b); sort(b+1,b+1+m,cmp); ans=N; fo(i,1,n+m) dad[i]=i; fo(i,1,m) { if (b[i].x==b[i].y) continue; x=b[i].x; y=b[i].y; tval[i+n]=b[i].b; tmax[i+n]=i+n; rx=get(x); ry=get(y); if (rx!=ry) { dad[rx]=ry; link(i+n,x); link(i+n,y); }else { makeroot(x); access(y); if (tval[tmax[y]]>b[i].b) { z=tmax[y]; cut(z,b[z-n].x); cut(z,b[z-n].y); link(i+n,x); link(i+n,y); } } if (get(1)==get(n)) { makeroot(1); access(n); splay(n,0); ans=min(ans,b[i].a+tval[tmax ]); } } if (ans==N) ans=-1; printf("%d\n",ans); }
相关文章推荐
- BZOJ 3669 . JZOJ 3754. 【NOI2014】魔法森林
- 【jzoj3754】【NOI2014】【魔法森林】【lct】
- 【BZOJ 3669】【NOI 2014】魔法森林 LCT+枚举边
- BZOJ 3669 NOI2014 魔法森林 SPFA
- [NOI2014]魔法森林
- [NOI2014]魔法森林|动态树
- [NOI 2014]魔法森林
- 3669 [Noi2014]魔法森林(LCT,最小生成树)
- [NOI2014魔法森林]LCT
- [Noi2014]魔法森林 (Link Cut Tree)
- 【NOI2014】bzoj3669 魔法森林
- BZOJ3669 [Noi2014]魔法森林
- uoj #3 (NOI 2014 魔法森林)
- BZOJ 3669: [Noi2014]魔法森林 LCT
- [NOI2014]魔法森林
- [bzoj3669][NOI2014]魔法森林
- BZOJ 3669: [Noi2014]魔法森林( LCT )
- 【bzoj3669】[Noi2014]魔法森林 LCT
- 【BZOJ3669】NOI2014-魔法森林(神奇的解法)
- [NOI2014]魔法森林