bzoj3669[Noi2014]魔法森林
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- #include <algorithm>
- #define maxn 150005
- #define maxm 100005
- #define pi pair<int,int>
- #define mp(a,b) make_pair(a,b)
- using namespace std;
- struct note{
- int u,v,a,b;
- }wi[maxm];
- int n,m,ans,fa[maxn],son[maxn][],val[maxn],sm[maxn],sm_id[maxn];
- bool rev[maxn];
- bool comp(note x,note y){
- if (x.a==y.a) return x.b<y.b;
- return x.a<y.a;
- }
- struct date{
- int which(int x){
- return son[fa[x]][]==x;
- }
- int isroot(int x){
- return son[fa[x]][]!=x&&son[fa[x]][]!=x;
- }
- void update(int x){
- sm_id[x]=x,sm[x]=val[x];
- if (son[x][]&&sm[son[x][]]>sm[x]) sm[x]=sm[son[x][]],sm_id[x]=sm_id[son[x][]];
- if (son[x][]&&sm[son[x][]]>sm[x]) sm[x]=sm[son[x][]],sm_id[x]=sm_id[son[x][]];
- }
- void pushdown(int x){
- if (rev[x]){
- rev[x]^=,swap(son[x][],son[x][]);
- if (son[x][]) rev[son[x][]]^=;
- if (son[x][]) rev[son[x][]]^=;
- }
- }
- void relax(int x){
- if (!isroot(x)) relax(fa[x]);
- pushdown(x);
- }
- void rotata(int x){
- int y=fa[x],d=which(x),dd=which(y);
- if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y];
- fa[son[x][d^]]=y,son[y][d]=son[x][d^];
- fa[y]=x,son[x][d^]=y;
- update(y);
- }
- void splay(int x){
- relax(x);
- while (!isroot(x)){
- if (isroot(fa[x])) rotata(x);
- else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x);
- else rotata(x),rotata(x);
- }
- update(x);
- }
- void access(int x){
- for (int p=;x;x=fa[x]){
- splay(x);
- son[x][]=p;
- update(x);
- p=x;
- }
- }
- void make_root(int x){
- access(x);
- splay(x);
- rev[x]^=;
- }
- void link(int x,int y){
- make_root(x);
- fa[x]=y;
- }
- void cut(int x,int y){
- make_root(x);
- access(y);
- splay(y);
- son[y][]=fa[x]=;
- update(y);
- }
- void split(int x,int y){
- make_root(x);
- access(y);
- splay(y);
- }
- int query(int x,int y){
- split(x,y);
- return sm[y];
- }
- pi find(int x,int y){
- split(x,y);
- return mp(sm_id[y],sm[y]);
- }
- int find_root(int x){
- access(x);
- splay(x);
- while (son[x][]) x=son[x][];
- return x;
- }
- }lct;
- int main(){
- // freopen("forest.in","r",stdin);
- // freopen("forest.out","w",stdout);
- memset(rev,,sizeof(rev));
- memset(fa,,sizeof(fa));
- memset(son,,sizeof(son));
- memset(val,,sizeof(val));
- memset(sm,,sizeof(sm));
- scanf("%d%d",&n,&m);
- for (int i=;i<=m;i++) scanf("%d%d%d%d",&wi[i].u,&wi[i].v,&wi[i].a,&wi[i].b);
- sort(wi+,wi+m+,comp);
- for (int i=;i<=n;i++) val[i]=,lct.update(i);
- ans=maxn;
- pi temp;
- for (int i=;i<=m;i++){
- int u=wi[i].u,v=wi[i].v;
- if (lct.find_root(u)!=lct.find_root(v)){
- val[n+i]=wi[i].b,lct.update(n+i);
- lct.link(n+i,u),lct.link(n+i,v);
- }else{
- temp=lct.find(u,v);
- if (temp.second<=wi[i].b) continue;
- else{
- int t=temp.first;
- lct.cut(wi[t-n].u,t),lct.cut(wi[t-n].v,t);
- val[n+i]=wi[i].b,lct.update(n+i);
- lct.link(n+i,u),lct.link(n+i,v);
- }
- }
- if (lct.find_root()!=lct.find_root(n)) continue;
- int t=lct.query(,n);
- ans=min(ans,t+wi[i].a);
- }
- if (ans>maxm) printf("-1\n");
- else printf("%d\n",ans);
- return ;
- }
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3669
题目大意:给定一个无向图,每条边有两个权值va,vb,要求选一条从1到n的路径,满足这条路径上点的max(va)+max(vb)最小,若没有从A到B的路径,则输出-1。
做法:初看这题,暴力写法:将边按va升序排序,枚举i,此时max(va)=vi,保证max(vb)最小即可,我们可以想到kruscal,并查集集维护即可,但是瓶颈在于每次都要将1~i的边按vb升序排序,在O(n)的加入,这种做法复杂度过高,不宜使用。
仔细想想:我们可以考虑用lct维护这个过程,考虑先将边按va升序排序,然后依次加入每一条边,此时max(va)=vi,保证max(vb)最小即可,加入该边时会有两种情况:
1.不形成环,则加入这条边,若节点1与节点n联通,则用1到n链上vb最大值+vi更新答案,否则不更新答案。
2.形成环,与lct模拟kruscal的过程一样,删掉原本那条链上vb权值最大的边,并加入这条边,若节点1与节点n联通,则用1到n链上vb最大值+vi更新答案,否则不更新答案。
lct+离线处理
bzoj3669[Noi2014]魔法森林的更多相关文章
- bzoj3669: [Noi2014]魔法森林 lct版
先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...
- [bzoj3669][Noi2014]魔法森林_LCT_并查集
魔法森林 bzoj-3669 Noi-2014 题目大意:说不明白题意系列++……题目链接 注释:略. 想法:如果只有1个参量的话spfa.dij什么的都上来了. 两个参量的话我们考虑,想将所有的边按 ...
- BZOJ3669[Noi2014]魔法森林——kruskal+LCT
题目描述 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节点1,隐士则住 ...
- BZOJ3669 [Noi2014]魔法森林(SPFA+动态加边)
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- BZOJ3669: [Noi2014]魔法森林(瓶颈生成树 LCT)
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 3558 Solved: 2283[Submit][Status][Discuss] Descript ...
- [bzoj3669][Noi2014]魔法森林——lct
Brief description 给定一个无向图,求从1到n的一条路径使得这条路径上最大的a和b最小. Algorithm Design 以下内容选自某HN神犇的blog 双瓶颈的最小生成树的感觉, ...
- bzoj3669: [Noi2014]魔法森林 lct
记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸 然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以 ...
- 沉迷Link-Cut tree无法自拔之:[BZOJ3669][Noi2014] 魔法森林
来自蒟蒻 \(Hero \_of \_Someone\) 的 \(LCT\) 学习笔记 $ $ 有一个很好的做法是 \(spfa\) ,但是我们不聊 \(spfa\) , 来聊 \(LCT\) \(L ...
- BZOJ3669 NOI2014魔法森林
按a从小到大排序,然后按b建图. 每次只需要找1~n中最大的b加当前的a计算答案即可. 这里还有一个小操作就是化边为点,把一条边的边权看做一个点的点权然后多连两条边. By:大奕哥 #include& ...
随机推荐
- 在C#中将String转换成Enum:
一: 在C#中将String转换成Enum: object Enum.Parse(System.Type enumType, string value, bool ignoreCase); 所以,我 ...
- npm淘宝镜像
前端开发会用到npm的包,但是国外的速度有时候很慢,幸运的是,淘宝做了镜像,一起来看看吧. https://npm.taobao.org/
- Spring TestContext测试框架搭建
同样是测试,JUnit和Spring TestContext相比,Spring TestContext优势如下: 1.Spring TestContext可以手动设置测试事务回滚,不破坏数据现场 2. ...
- C/C++实践笔记 003
数据结构与算法程序=数据结构+算法语言是一种工具语言工具(c,c++)--程序设计方法(面向过程.面向对象)——数据结构(二叉树.队列.栈.红黑树.链表……)——算法(快速排序算法.冒泡排序算法.选择 ...
- 我的Logo设计简史
近日,日本东京奥运会会微因涉嫌抄袭而被弃用的新闻引起设计界的一翻热论.在此我想到自己的LOGO设计,虽说并一定不好看甚至自己看回来都觉得略丑,但 几乎没有过抄袭的念头.有句话说,不想当设计师的程序猿不 ...
- 让 innerHTML 进来的 script 代码跑起来
今天来简单聊聊如何让 innerHTML 进来的 scrip 代码跑起来的问题. 前台请求一个接口,接口返回一些 HTML 标签拼接成的字符串,以供前端直接 innerHTML 生成 DOM 元素,这 ...
- ASP.NET 系列:单元测试之SmtpClient
使用SmtpClient发送Email时,我们可以创建ISmtpClient接口和SmtpClientWrapper适配类,在单元测试中对ISmtpClient进行Mock或自定义FackeSmtpC ...
- iOS10-- snapshotViewAfterScreenUpdates 失效
如果snapshotViewAfterScreenUpdates失效, 用这个方法替代, 不过要自己创建ImageView 替代方式: - (UIImage *)imageFromView:(UIVi ...
- 常用数据库高可用和分区解决方案(1) — MySQL篇
在本文中我们将会讨论MySQL.Oracle.MongoDB.Redis以及Oceanbase数据库,大家可能会奇怪为什么看不到有名关系型数据库MSSQL.DB2或者有名NoSQL数据库Hbase.L ...
- 使用ContentProvider进行应用程序间的数据交互
什么是ContentProvider: ContentProvider用来管理数据的访问规则.它允许你的应用程序向外界暴露需要被访问的数据. 是Android的四大组件之一. ContentProvi ...