记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸

然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以下两种情况:

1) 若u,v已连通,则找出u->v上最大的b',若b<b',则替换之,同时更新答案,注意e一定经过1->n,因为去掉b'所在边时1,n一定不连通,若加上e后1,n连通,则必经过e,由于a是有序的,所以a是路径上最大的a,用a+MAX_b[1->n]更新答案即可。

2)否则,直接加入边e;

显然以上操作可以用lct处理。

对于维护边的信息,考虑把边看成点,与原来的真正的节点一起构成一棵(或多棵)lct,将边的信息存在对应的点上,并保证真正的结点不会对答案产生影响(相当于只起连通的作用),对于这道题,保证w[x]=0(x是结点的结点),x(x是边的结点)即可。

 #include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cstdio> using namespace std; // The default source begin-----------
const int MXD=~0u>>;
const int D=;
char in[D],out[*],*I=in,*O=out;
#define gc (*I++)
#define pc(x) ((*O++)=x)
#define tQ template <typename Q>
tQ void gt(Q&x) {
static char c,f;
for(f=;c=gc,!isdigit(c);)if(c=='-') f=;
for(x=;isdigit(c);c=gc) x=(x<<) + (x<<) +c-'';
f && (x=-x);
}
tQ void pt(Q x){
static char stk[];
static int top;
top=;
if(x==) pc('');
for(;x;x/=) stk[++top] = x%+'';
for(;top;top--) pc(stk[top]);
}
// The default source end----------- const int Maxn=,Maxm=;
int n,m;
struct Edge{
int u,v,a,b;
inline bool operator < (const Edge&rhs) const {
return a<rhs.a || (a==rhs.a && b<rhs.b);
}
inline void read() {
gt(u),gt(v),gt(a),gt(b);
}
}edges[Maxm]; int ch[Maxn+Maxm][],p[Maxn+Maxm],flip[Maxn+Maxm],mx[Maxn+Maxm],w[Maxn+Maxm]; #define l ch[x][0]
#define r ch[x][1]
void update(int x){
if(!x) return;
mx[x]=x;
if(w[mx[l]]>w[mx[x]]) mx[x]=mx[l];
if(w[mx[r]]>w[mx[x]]) mx[x]=mx[r];
}
void down(int x) {
if(!x || !flip[x]) return;
swap(l,r);
flip[l]^=;
flip[r]^=;
flip[x]=;
}
#undef l
#undef r
inline bool isroot(int x) {
return ch[p[x]][]!=x && ch[p[x]][]!=x;
}
inline void rotate(int x){
int y=p[x],z=p[y];
int l=ch[y][]==x,r=l^;
if(!isroot(y)){
ch[z][ch[z][]==y]=x;
}
p[y]=x;
p[ch[x][r]]=y;
p[x]=z; ch[y][l]=ch[x][r];
ch[x][r]=y; update(y);
// update(x);
} int stk[Maxn],top;
inline void splay(int x){
stk[top=]=x;
for(int t=x;!isroot(t);stk[++top]=t=p[t]);
for(;top;top--) down(stk[top]);
for(;!isroot(x);){
int y=p[x],z=p[y];
if(!isroot(y)) {
if( (ch[y][]==x) ^ (ch[z][]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
update(x);
} inline void access(int x) {
for(int t=;x;x=p[t=x]){
splay(x);
ch[x][]=t;
update(x);
}
} inline void newroot(int x) {
access(x);
splay(x);
flip[x]^=;
} inline void n_as(int u,int v){
newroot(u);
access(v);
splay(v);
} inline void Cut(int x,int y) {
n_as(x,y);
ch[y][]=p[x]=;
update(x);
} inline void Link(int x,int y) {
newroot(x);
p[x]=y;
} int fa[Maxn];
int Find(int x) {
return x==fa[x]?x:fa[x]=Find(fa[x]);
} inline bool Union(int x,int y){
x=Find(x);y=Find(y);
if(x==y) return ;
return fa[x]=y,;
} inline void ufs_init(int n) {
for(int i=;i<=n;i++) fa[i]=i;
} inline void init() {
gt(n),gt(m);
for(int i=;i<=m;i++) edges[i].read();
ufs_init(n);
} inline int getroot(int x) {
for(access(x),splay(x);ch[x][];x=ch[x][]);
return x;
} inline void work() {
sort(edges+,edges+m+);
int ans=MXD;
for(int i=;i<=m;i++) {
const Edge& e=edges[i];
w[i+n]=e.b;
if(Union(e.u,e.v)) {
Link(e.u,i+n);
Link(e.v,i+n);
}else {
n_as(e.u,e.v);
int t=mx[e.v];
if(w[t] > e.b) {
Cut(edges[t-n].u,t);
Cut(edges[t-n].v,t);
Link(e.u,i+n);
Link(e.v,i+n);
}
}
newroot();
if(getroot(n)==) {
access(n);
splay(n);
ans = min (ans,e.a + w[mx[n]]);
}
}
printf("%d\n",ans==MXD?-:ans);
} int main() {
#ifdef DEBUG
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
#endif
fread(in,,D,stdin);
init();
work(); return ;
}

bzoj3669: [Noi2014]魔法森林 lct的更多相关文章

  1. bzoj3669: [Noi2014]魔法森林 lct版

    先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...

  2. [bzoj3669][Noi2014]魔法森林——lct

    Brief description 给定一个无向图,求从1到n的一条路径使得这条路径上最大的a和b最小. Algorithm Design 以下内容选自某HN神犇的blog 双瓶颈的最小生成树的感觉, ...

  3. BZOJ 3669: [Noi2014]魔法森林( LCT )

    排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...

  4. bzoj 3669: [Noi2014]魔法森林 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec  ...

  5. [NOI2014]魔法森林 LCT

    题面 [NOI2014]魔法森林 题解 一条路径的代价为路径上的\(max(a[i]) + max(b[i])\),因为一条边同时有$a[i], b[i]$2种权值,直接处理不好同时兼顾到,所以我们考 ...

  6. loj2245 [NOI2014]魔法森林 LCT

    [NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...

  7. 【BZOJ3669】[Noi2014]魔法森林 LCT

    终于不是裸的LCT了...然而一开始一眼看上去这是kruskal..不对,题目要求1->n的路径上的每个点的两个最大权值和最小,这样便可以用LCT来维护一个最小生成路(瞎编的...),先以a为关 ...

  8. BZOJ3669[Noi2014]魔法森林——kruskal+LCT

    题目描述 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节点1,隐士则住 ...

  9. BZOJ3669: [Noi2014]魔法森林(瓶颈生成树 LCT)

    Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 3558  Solved: 2283[Submit][Status][Discuss] Descript ...

随机推荐

  1. 网络编程(学习整理)---2--(Udp)实现简单的控制台聊天室

    1.UDP协议: 总结一下,今天学习的一点知识点! UDP也是一种通信协议,常被用来与TCP协议作比较!我们知道,在发送数据包的时候使用TCP协议比UDP协议安全,那么到底安全在哪里呢?怎么理解呢! ...

  2. 主成份分析PCA

    Data Mining 主成分分析PCA 降维的必要性 1.多重共线性--预测变量之间相互关联.多重共线性会导致解空间的不稳定,从而可能导致结果的不连贯. 2.高维空间本身具有稀疏性.一维正态分布有6 ...

  3. &nbsp; 与 空格的区别

    nbsp 是 Non-Breaking SPace的缩写,即“不被折断的空格”,当两个单词使用   连接时,这两个单词就不会被分隔为2行,如下面 <div id="div1" ...

  4. 利用sfntly的sfnttool.jar提取中文字体

    雨忆博客中提到了sfntly(具体介绍可以看:https://code.google.com/p/sfntly/),利用其中sfnttool.jar就可以提取只包含指定字符的字体,如果想在页面中通过@ ...

  5. iOS适配:Masonry介绍与使用实践:快速上手Autolayout

    随着iPhone的手机版本越来越多, 那么对于我们广大的开发者来说就是很悲催,之前一直使用代码里面layout的约束来适配, 现在推荐一个第三方Masonry,上手块,操作简单,只能一个字形容他 “爽 ...

  6. css实现三角的一些方法

    css实现三角没有想象中的那么难,只要明白border的各种属性的意思就很好明白css三角是如何实现的. 一下是几个很简单的例子:   css三角形状的制作:     css样式:    .trian ...

  7. 递归删除.DS_Store文件

    删除svn文件 sudo find . -name ".DS_Store" -exec rm -r {} \; sudo find . -name ".git" ...

  8. E: Some packages could not be authenticated

    问题:          在Ubuntu上,安装软件时出现了“E: Some packages could not be authenticated”错误. 原因:     表示系统无法验证这个软件包 ...

  9. cut 命令使用

    cut -d -f cut -c cut -d分隔符 -f分割后取的第几个字符串 cut -c从哪个字符开始取

  10. java和javascript获取word文档的书签位置对比

    1.javascript:把IE浏览器的activex都打开,使用如下网页,可以看到书签顺序和位置: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...