BZOJ3669/UOJ3 魔法森林(LCT)
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
题目链接:BZOJ
正解:LCT
解题报告:
考虑这种两维约束的问题,一般都是限制一维,最小化另一维度。
那么我按a排序之后,一条一条往里面加,如果不连通,直接加进去,否则肯定是查询一下原来的边上的最大的b权值。
如果当前b权值大于最大的b值就不管,否则应该删掉这条最大的边,把这条新的边加进去。
显然加边删边用LCT就可以解决,而边权的查询如何维护呢?
如果是点权就很好办了,我们不妨把边权想点办法变成点权。
直接在这条边连接的两个点之间新建一个点,作为中转点,点权就是原边边权。这样我们就巧妙地把边权转换成好维护的点权了。
考虑这样做的正确性,因为辅助树实质上与原树并无关联,始终都能保持原树的相对位置。所以加入的这个虚点不会被剥离出来。
又因为一些SB的细节错误调了很久...
//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef complex<double> C;
const double pi = acos(-1);
const int MAXN = 250011;
const int MAXM = 100011;
int n,m,tr[MAXN][2],tag[MAXN],father[MAXN],ans,pos,F[MAXN];
int top,stack[MAXN],a[MAXN],mx[MAXN],from[MAXN],match[MAXN][2];
struct edge{ int x,y,a,b; }e[MAXM];
inline bool cmpa(edge q,edge qq){ if(q.a==qq.a) return q.b<qq.b; return q.a<qq.a; }
inline bool isroot(int x){ return (tr[father[x]][0]!=x) && (tr[father[x]][1]!=x); }
inline void upd(int x,int y){ if(mx[y]>mx[x]) { mx[x]=mx[y]; from[x]=from[y]; } }
inline int find(int x){ if(F[x]!=x) F[x]=find(F[x]); return F[x]; }
inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline void update(int x){
mx[x]=a[x]; from[x]=x;
int l=tr[x][0],r=tr[x][1];
if(l) upd(x,l);
if(r) upd(x,r);
} inline void pushdown(int x){
if(tag[x]==0) return ;
tag[tr[x][0]]^=1; tag[tr[x][1]]^=1;
tag[x]=0;//!!!
swap(tr[x][0],tr[x][1]);
} inline void rotate(int x){
int y,z; y=father[x]; z=father[y];
int l,r; l=(tr[y][1]==x); r=l^1;
if(!isroot(y)) tr[z][(tr[z][1]==y)]=x;
father[x]=z; father[y]=x;
father[tr[x][r]]=y; tr[y][l]=tr[x][r]; tr[x][r]=y;
update(y); update(x);
} inline void splay(int x){
top=0; stack[++top]=x; int y,z;
for(int i=x;!isroot(i);i=father[i]) stack[++top]=father[i];
for(int i=top;i>=1;i--) pushdown(stack[i]); while(!isroot(x)) {
y=father[x]; z=father[y];
if(!isroot(y)) {
if((tr[y][0]==x) ^ (tr[z][0]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
} inline void access(int x){
int last=0;
while(x) {
splay(x);
tr[x][1]=last;
update(x);/*!!!*/
last=x;
x=father[x];
}
} inline void move_to_root(int x){
access(x);
splay(x);
tag[x]^=1;
} inline void link(int x,int y){
move_to_root(x);
father[x]=y;
//splay(x);
} inline void cut(int x,int y){
move_to_root(x); access(y); splay(y);
tr[y][0]=father[x]=0; update(y);/*!!!*/
} inline void build(edge b){
n++; a[n]=b.b; match[n][0]=b.x; match[n][1]=b.y;
link(b.x,n);
link(b.y,n);
} inline int query(int x,int y){
move_to_root(x);
access(y);
splay(y);//!!!
pos=from[y];
return mx[y];
} inline void work(){
n=getint(); m=getint(); for(int i=1;i<=m;i++) { e[i].x=getint(); e[i].y=getint(); e[i].a=getint(); e[i].b=getint(); }
sort(e+1,e+m+1,cmpa); int now; ans=(1<<30); int savn=n;
for(int i=n+m;i>=1;i--) F[i]=i;
for(int i=1;i<=m;i++) {
if(find(e[i].x)!=find(e[i].y)) {
build(e[i]);
F[find(e[i].x)]=find(e[i].y);
if(find(1)==find(savn))
ans=min(ans,query(1,savn)+e[i].a);
continue;
}
now=query(e[i].x,e[i].y);
if(now<=e[i].b) continue;
cut(pos,match[pos][0]);
cut(pos,match[pos][1]);
build(e[i]);
if(find(1)==find(savn))
ans=min(ans,e[i].a+query(1,savn));
}
if(ans==(1<<30)) printf("-1");
else printf("%d",ans);
} int main()
{
work();
return 0;
}
BZOJ3669/UOJ3 魔法森林(LCT)的更多相关文章
- bzoj3669: [Noi2014]魔法森林 lct版
先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...
- bzoj3669: [Noi2014]魔法森林 lct
记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸 然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以 ...
- [bzoj3669][Noi2014]魔法森林——lct
Brief description 给定一个无向图,求从1到n的一条路径使得这条路径上最大的a和b最小. Algorithm Design 以下内容选自某HN神犇的blog 双瓶颈的最小生成树的感觉, ...
- [BZOJ3669] [NOI2004] 魔法森林 LCT维护最小生成树
题面 一开始看到这道题虽然知道是跟LCT维护最小生成树相关的但是没有可以的去想. 感觉可以先二分一下总的精灵数,但是感觉不太好做. 又感觉可以只二分一种精灵,用最小生成树算另一种精灵,但是和似乎不单调 ...
- 【BZOJ3669】[Noi2014]魔法森林 LCT
终于不是裸的LCT了...然而一开始一眼看上去这是kruskal..不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的...),先以a为关 ...
- BZOJ3669[Noi2014]魔法森林——kruskal+LCT
题目描述 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节点1,隐士则住 ...
- BZOJ3669: [Noi2014]魔法森林(瓶颈生成树 LCT)
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 3558 Solved: 2283[Submit][Status][Discuss] Descript ...
- [bzoj3669][Noi2014]魔法森林_LCT_并查集
魔法森林 bzoj-3669 Noi-2014 题目大意:说不明白题意系列++……题目链接 注释:略. 想法:如果只有1个参量的话spfa.dij什么的都上来了. 两个参量的话我们考虑,想将所有的边按 ...
- BZOJ 3669: [Noi2014]魔法森林( LCT )
排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...
随机推荐
- IDEA 设置代码模板
一.代码模板 参考: IntelliJ IDEA 使用(一)基本设置与类.方法模板设置 - 云 + 社区 - 腾讯云 文件代码模板的使用 - IntelliJ IDEA 使用教程 - 极客学院 Wik ...
- Ad Exchange
品友互动-基于大数据技术的人工智能决策平台 http://www.ipinyou.com.cn/about?flag=milestones
- XML 解析之 dom4j 解析器
dom4j 的使用需要导入 jar 包, 包括: dom4j-1.6.1 和 jaxen-1.1-beta 步骤: 在项目目录下,"Folder" 创建一个 lib 文件夹 复制 ...
- js生成二维码/html2canvas生成屏幕截图
1.需求简述 (1) 最初需求: 根据后台接口获取url,生成一个二维码,用户可以长按保存为图片.(这时的二维码只是纯黑白像素构成的二维码) 方案1: 使用jquery.qrcode.min.js插件 ...
- Tomcat的session
创建session 在具体说明session的创建过程之前,先看一下BS访问模型: browser发送Http request: tomcat内核Http11Processor会从HTTP requ ...
- fopen() r+、w+属性详解
r+具有读写属性,从文件头开始写,保留原文件中没有被覆盖的内容: w+具有读写属性,写的时候如果文件存在,会被清空,从头开始写. r 打开只读文件,该文件必须存在. r+ 打开可读写的文件,该文件必须 ...
- Angular学习笔记—创建一个angular项目
开始项目前,你需要先安装node和npm,然后执行npm install -g @angular/cli安装Angular CLI. 如何安装node.js和npm npm使用介绍 1.安装angul ...
- Java排序算法总结(转载)
排序算法 平均时间复杂度 冒泡排序 O(n2) 选择排序 O(n2) 插入排序 O(n2) 希尔排序 O(n1.5) 快速排序 O(N*logN) 归并排序 O(N*logN) 堆排序 O(N*log ...
- 正则表达式 - JavaScript描述
正则表达式 - JavaScript描述 概述 正则表达式是被用来匹配字符串中的字符组合的模式.在JavaScript中,正则表达式也是对象. 创建正则表达式 var re = /abc/; // 使 ...
- c++ ScopeExitGuard
说到Native Languages就不得不说资源管理,因为资源管理向来都是Native Languages的一个大问题,其中内存管理又是资源当中的一个大问题,由于堆内存需要手动分配和释放,所以必须确 ...