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) ------------------------------------------------------------------- ...
随机推荐
- IE、FF脚本兼容性问题
1.window.event IE有这个对象:FF没有,FF通过参数传递 2.获取事件源 IE:srcElement FF:target 3.添加与去除事件 IE:element.attachEven ...
- css生成三角形
转载:http://www.cnblogs.com/lhb25/p/css-and-css3-triangle.html Triangle Up 1 2 3 4 5 6 7 #triangle ...
- Canvas-图片填充-预加载
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- 【Python之路】第二十一篇--Memcached、Redis
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...
- bitmap位图法
位图法定义 位图法就是bitmap的缩写,所谓bitmap,是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况.通常是用来判断某个数据存不存在的. 例如,要判断一千万个人的状态,每 ...
- mysql 建立表之间关系 练习 2
创建数据库db6 create database db6 charset=utf8; user db6; # 创建班级表 mysql) not null unique); Query OK, rows ...
- Xilinx中解决高扇出的方法
Fanout,即扇出,指模块直接调用的下级模块的个数,如果这个数值过大的话,在FPGA直接表现为net delay较大,不利于时序收敛.因此,在写代码时应尽量避免高扇出的情况.但是,在某些特殊情况下, ...
- 在python中有多少种运算符?解释一下算术运算符
在python中,我们有7种运算符:算术运算符.关系运算符.赋值运算符.逻辑运算符.位运算符.成员运算符.身份运算符 我们有7个算术运算符,能让我们对数值进行算术计算 1.加号(+),将两个值相加 2 ...
- http post url参数封装(key token 及校验码)
post请求本来是一种很常见的web请求方式,相信许多项目都有一系列的封装工具类. 今天遇着一个特殊的需求. 需要在post的请求url内封装相应的token 与及key相关的值,这就奇怪了,url封 ...
- Spring 知识点总结
一.Spring 概述 1. 什么是spring? Spring 是个java企业级应用的开源开发框架.Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用.Sprin ...