[NOI2014]魔法森林
2018-03-08 16:30
302 查看
题目
[NOI2014]魔法森林解析
要求a 与 b 的总和最小 可以按a排序 再以b为权值维护一颗树 LCT维护最小生成树要解决的问题
将每一条边变为一个点 边权变为点权 举个栗子: u->v有一条边权为w的边 怎LCT连边方式为 u->new->v new的点权为w
不断维护最小生成树 如果新加入的边的 u与v不连通 直接加 如果连通 求u到v路上的最大边权边 将它切掉(其实是切两条边)再加边
边权为b
代码
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int maxn=100000+10; int n,m,blow; int ans=0x7fffffff; struct node1 { int a,b,start,end; bool operator < (const node1 & o) const { return a<o.a; } }edge[maxn]; struct node { int fa,ch[2]; bool reverse,is_root; int data,id; int max1,id1; }T[maxn*10]; int getson(int x) { return T[T[x].fa].ch[1]==x; } void update(int x) { if(x>n) T[x].max1=T[x].data,T[x].id1=T[x].id; else T[x].max1=0; if(T[x].ch[1] && T[x].max1<T[T[x].ch[1]].max1) { T[x].max1=T[T[x].ch[1]].max1; T[x].id1=T[T[x].ch[1]].id1; } if(T[x].ch[0] && T[x].max1<T[T[x].ch[0]].max1) { T[x].max1=T[T[x].ch[0]].max1; T[x].id1=T[T[x].ch[0]].id1; } } void rotate(int x) { int son=getson(x),fa=T[x].fa; int g=T[fa].fa; T[fa].ch[son]=T[x].ch[son^1]; T[fa].fa=x; T[x].fa=g; if(T[x].ch[son^1]) T[T[x].ch[son^1]].fa=fa; T[x].ch[son^1]=fa; if(!T[fa].is_root) T[g].ch[T[g].ch[1]==fa]=x; else T[x].is_root=true,T[fa].is_root=false; update(fa); update(x); } void pushreverse(int x) { if(!x) return; swap(T[x].ch[0],T[x].ch[1]); T[x].reverse^=1; } void pushdown(int x) { if(T[x].reverse) { pushreverse(T[x].ch[0]); pushreverse(T[x].ch[1]); T[x].reverse=false; } } void push(int x) { if(!T[x].is_root) push(T[x].fa); pushdown(x); } void splay(int x) { push(x); for(int fa; !T[x].is_root; rotate(x)) { if(!T[fa=T[x].fa].is_root) rotate(getson(fa)==getson(x)? fa : x); } } void access(int x) { for(int y=0; x; x=T[y=x].fa) { splay(x); T[T[x].ch[1]].is_root=true; T[T[x].ch[1]=y].is_root=false; update(x); } } void mroot(int x) { access(x); splay(x); pushreverse(x); } int findroot(int x) { while(T[x].fa) x=T[x].fa; return x; } void link(int x,int y) { mroot(x); T[x].fa=y; } void cut(int x,int y) { mroot(x); access(y); splay(y); T[x].is_root=true; T[x].fa=T[y].ch[0]=0; } int solve(int x) { blow=x; int x1=edge[blow].start,y=edge[blow].end; int xx=findroot(x1),yy=findroot(y); // cout<<x<<' '<<x1<<' '<<y<<' '<<xx<<' '<<yy<<endl; if(xx!=yy) { T[blow+n].data=edge[blow].b; T[blow+n].id=blow+n; link(n+blow,x1); link(n+blow,y); } else { mroot(x1); access(y); splay(y); if(T[y].max1>edge[blow].b) { // cout<<x<<' '<<T[y].id1<<endl; T[T[y].id1].id=T[T[y].id1].data=0; int cc=T[y].id1;//¼Çϵ±Ç°½Úµã£¬cutÖ®ºó¿ÉÄÜ»á¸Ä±ä cut(edge[cc-n].start,cc); cut(cc,edge[cc-n].end); T[blow+n].data=edge[blow].b; T[blow+n].id=blow+n; link(x1,n+blow); link(n+blow,y); } } xx=findroot(1),yy=findroot(n); if(xx!=yy) return -1; mroot(1); access(n); splay(n); return T .max1; } int main() { freopen("magicalforest.in","r",stdin); freopen("magicalforest.out","w",stdout); scanf("%d %d",&n,&m); for(int i=0; i<=n+m; i++) { T[i].is_root=true; } for(int i=1; i<=m; i++) { scanf("%d %d %d %d",&edge[i].start,&edge[i].end,&edge[i].a,&edge[i].b); } sort(edge+1,edge+m+1); bool flag=false; blow=1; for(int i=1; i<=m; i++) { /* if(i==327) { int tmp=solve(i); if(tmp!=-1 && tmp+i<ans) { flag=true; ans=min(ans,tmp+edge[i].a); } continue; }*/ int tmp=solve(i); if(tmp!=-1 && tmp+edge[i].a<ans) { flag=true; ans=min(ans,tmp+edge[i].a); } } cout<<(flag? ans:-1)<<endl; return 0; }
相关文章推荐
- ☆ [NOI2014] 魔法森林 「LCT动态维护最小生成树」
- 【bzoj3669】[Noi2014]魔法森林
- BZOJ3669 NOI2014魔法森林
- 【BZOJ3669】【UOJ3】【NOI2014】魔法森林
- BZOJ 3669: [Noi2014]魔法森林
- bzoj 3669: [Noi2014]魔法森林
- 【BZOJ3669】【NOI2014】魔法森林 LCT
- 【bzoj3669】【noi2014】【魔法森林】【spfa】
- 【BZOJ】3669: [Noi2014]魔法森林(lct+特殊的技巧)
- [NOI2014]魔法森林
- 【BZOJ 3669】【NOI 2014】魔法森林 LCT+枚举边
- 【jzoj3754】【NOI2014】【魔法森林】【lct】
- BZOJ_3669_[Noi2014]魔法森林_LCT
- [BZOJ3669][Noi2014]魔法森林 && LCT
- bzoj3669【NOI2014】魔法森林
- [NOI2014]魔法森林(动态加边+SPFA)
- bzoj 3669: [Noi2014]魔法森林
- UOJ #3(【NOI2014】魔法森林-LCT区间最值)
- [置顶] link cut tree 学习小结【NOI2014】魔法森林
- [NOI 2014]魔法森林