[省选前题目整理][BZOJ 3669]魔法森林(LCT)
来源:互联网 发布:淘宝搞笑收件人名字男 编辑:程序博客网 时间:2024/06/05 18:34
题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=3669
思路
这个题本来是个SPFA的题。。。但是正解不好想,倒是LCT的暴力比较好想。。。
用Kruscal的方法时刻维护一个生成树,按照a升序加边,并用LCT维护这个生成树,具体做法就是把每个边看成是LCT的结点,点也看成是LCT的结点,加入一条边时,就link一个点和边,link另一个点和边,但是与Kruscal不同的是,如果当前的边的两个端点已经联通了,但是这两个端点路径上的b最大的边比当前的边的b值大,仍然可以加入这条边,并把原来两个端点路径上b最大的那条边cut掉,在上述过程中,如果任何时候发现起点和终点已经联通,就更新答案。。。
代码
其实我只用了半个小时打好LCT,结果一直过不了样例,以为LCT写错了。。。搞了半天才发现LCT没问题,是我先对LCT结点标记初始化了,再给边排的序。。。我靠。。。
#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#define MAXN 200000#define lson ch[o][0]#define rson ch[o][1]using namespace std;int ch[MAXN][2],fa[MAXN],maxtag[MAXN],val[MAXN]; //maxtag[i]=区间最大值的对应子树根节点编号!!!int stack[MAXN],top=0;bool rev[MAXN];bool isRoot(int o){ return ch[fa[o]][0]!=o&&ch[fa[o]][1]!=o;}void pushup(int o){ maxtag[o]=o; if(val[maxtag[lson]]>val[maxtag[o]]) maxtag[o]=maxtag[lson]; if(val[maxtag[rson]]>val[maxtag[o]]) maxtag[o]=maxtag[rson];}void pushdown(int o){ //if(!o) return; if(rev[o]) { rev[lson]^=1; rev[rson]^=1; swap(lson,rson); rev[o]=false; }}void rot(int x){ int y=fa[x],z=fa[y]; int p,q; if(ch[y][0]==x) p=0; else p=1; q=p^1; if(!isRoot(y)) { if(ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x; } fa[x]=z,fa[y]=x; ch[y][p]=ch[x][q]; fa[ch[x][q]]=y; ch[x][q]=y; pushup(y); pushup(x);}void splay(int x){ top=0; stack[++top]=x; for(int i=x;!isRoot(i);i=fa[i]) stack[++top]=fa[i]; for(int i=top;i>=1;i--) pushdown(stack[i]); //!!!!!! while(!isRoot(x)) { int y=fa[x],z=fa[y]; if(!isRoot(y)) { if((ch[y][0]==x)==(ch[z][0]==y)) rot(y); else rot(x); } rot(x); }}void access(int x){ int tmp=0; while(x) { splay(x); ch[x][1]=tmp; pushup(x); tmp=x; x=fa[x]; }}void makeroot(int x){ access(x); splay(x); rev[x]^=1;}void link(int x,int y) //y是x父亲{ makeroot(x); fa[x]=y;}void cut(int x,int y) //y是x父亲{ makeroot(x); access(y); splay(y); if(ch[y][0]==x) ch[y][0]=fa[x]=0;}int query(int x,int y) //询问路径xy上的最大边{ makeroot(x); access(y); splay(y); return maxtag[y];}int f[MAXN];int findSet(int x){ if(f[x]==x) return f[x]; return f[x]=findSet(f[x]);}struct edge{ int u,v,a,b;}edges[MAXN];int n,m;bool cmp(edge a,edge b){ return a.a<b.a;}void solve(int i) //在已经联通的块中加入边i{ int old=query(edges[i].u,edges[i].v); if(val[old]>edges[i].b) { cut(edges[old-n].u,old); cut(edges[old-n].v,old); link(edges[i].u,n+i); link(edges[i].v,n+i); }}void work(){ for(int i=0;i<MAXN;i++) f[i]=i; int ans=0x3f3f3f3f; for(int i=1;i<=m;i++) { int rootu=findSet(edges[i].u),rootv=findSet(edges[i].v); if(rootu!=rootv) { f[rootu]=rootv; link(edges[i].u,n+i); link(edges[i].v,n+i); } else solve(i); if(findSet(1)==findSet(n)) //起点和终点已经在MST中联通 ans=min(ans,val[query(1,n)]+edges[i].a); } if(ans!=0x3f3f3f3f) printf("%d\n",ans); else printf("-1\n");}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&edges[i].u,&edges[i].v,&edges[i].a,&edges[i].b); sort(edges+1,edges+m+1,cmp); //!!!!!fuck!!!!! for(int i=1;i<=m;i++) { val[n+i]=edges[i].b; maxtag[n+i]=n+i; } work(); return 0;}
0 0
- [省选前题目整理][BZOJ 3669]魔法森林(LCT)
- BZOJ 3669 魔法森林 LCT
- BZOJ 3669 [Noi2014]魔法森林 LCT
- 【LCT】BZOJ 3669: [Noi2014]魔法森林
- bzoj 3669 NOI2014 魔法森林 [LCT]
- BZOJ 3669 [Noi2014]魔法森林 LCT
- BZOJ 3669: [Noi2014]魔法森林 LCT
- BZOJ 3669 [Noi2014]魔法森林 Kruskal+LCT
- [BZOJ]3669: [Noi2014]魔法森林 lct
- BZOJ 3669 NOI 2014 魔法森林 最短路/LCT
- 【BZOJ】【P3669】【NOI2014】【魔法森林】【题解】【LCT】
- 3669: [Noi2014]魔法森林 LCT
- bzoj-3669 魔法森林
- bzoj 3669 魔法森林
- NOI2014-魔法森林(LCT)
- [NOI2014魔法森林]LCT
- uoj 魔法森林--LCT
- NOI2014魔法森林--LCT
- Java垃圾回收
- JavaScript权威指南_83_第10章_正则表达式的模式匹配_10.1.2-正则表达式的定义-字符类
- armeabi和armeabi-v7a
- JavaScript权威指南_84_第10章_正则表达式的模式匹配_10.1.3-正则表达式的定义-重复
- 服务器挂掉原因
- [省选前题目整理][BZOJ 3669]魔法森林(LCT)
- git 基础教程
- 带权二叉树路径所代表的所有整数和
- Mule 实现WebService代理
- cocos2dx 执行流程分析
- 社説 20150324 免震ゴム不正 建物の信頼回復へ対応を急げ
- 象棋问题
- JavaScript权威指南_85_第10章_正则表达式的模式匹配_10.1.4-正则表达式的定义-选择、分组、引用
- redis tomcat session共享 资料整理