Vijos1865 NOI2014 魔法森林 LCT维护生成树
基本思路:
首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值
如果加边过程中生成了环,则删除环中weightB最大的边
由于是无向图,点之间没有拓扑序,所以在建立LCT模型时,可以将原图的边也视为点,这样就转化成了维护路径上的点权最大值(Orz Hzwer)
点的连通性可以用并查集维护
AC code:(其实Splay双旋一次时只需要进行3次update,而代码中舍弃了这个优化)
#include <cstdio>
#include <cstring>
#include <algorithm>
;
;
const int inf=0x3f3f3f3f;
struct Edge
{
int u,v;
int weightA,weightB;
void assign(int _u,int _v,int _wa,int _wb)
{
u=_u; v=_v; weightA=_wa; weightB=_wb;
}
bool operator < (const Edge& other) const
{
return this->weightA < other.weightA;
}
};
Edge elist[maxM];
inline int getMaxIdx(int u,int v)
{
return elist[u].weightB > elist[v].weightB ? u : v;
} //Let elist[0].weightB = -inf
struct Splay
{
int idx;
int maxIdx;
bool rev;
Splay* child[];
Splay* parent;
void init(int id)
{
idx=maxIdx=id;
rev=false;
child[]=child[]=parent=;
}
bool isRoot()
{
if(!parent) return true;
] && ];
}
void update()
{
maxIdx=idx;
]) maxIdx=getMaxIdx(]->maxIdx);
]) maxIdx=getMaxIdx(]->maxIdx);
}
void reverse()
{
if(!isRoot()) parent->reverse();
if(rev) {
std::swap(child[],child[]);
]) child[]->rev ^= ;
]) child[]->rev ^= ;
;
}
}
; }
void rotate(int dir)
{
Splay* temp=parent;
this->parent=temp->parent;
if(parent)
{
]) parent->child[]=this;
]) parent->child[]=this;
}
temp->child[dir^]=this->child[dir];
if(child[dir]) child[dir]->parent=temp;
child[dir]=temp;
temp->parent=this;
temp->update();
this->update();
}
void splay()
{
reverse();
while(!isRoot())
{
);
]) st|=;
;
if(!parent->isRoot())
{
]) st|=;
;
}
switch(st)
{
: rotate(); break;
: rotate(); break;
: parent->rotate(); ); break;
: rotate(); rotate(); break;
: rotate(); rotate(); break;
:parent->rotate(); ); break;
}
}
}
};
Splay node[maxN+maxM];
int access(int idx)
{
Splay *cur,*last;
;cur;last=cur,cur=cur->parent)
{
cur->splay();
cur->child[]=last;
cur->update();
}
return last->maxIdx;
}
inline void setAsRoot(int idx)
{
access(idx);
node[idx].splay();
node[idx].setRev();
}
inline void link(int u,int v)
{
setAsRoot(u);
node[u].parent=node+v;
}
inline void cut(int u,int v)
{
setAsRoot(u);
access(v);
node[v].splay();
node[v].child[]=node[u].parent=;
node[v].update();
}
inline int query(int u,int v)
{
setAsRoot(u);
return access(v);
}
int N,M;
int center[maxN];
int getCenter(int idx)
{
return center[idx]==idx ? idx :
center[idx]=getCenter(center[idx]);
}
void input()
{
scanf("%d%d",&N,&M);
int u,v,wa,wb;
;i<=M;i++)
{
scanf("%d%d%d%d",&u,&v,&wa,&wb);
if(u==v) { --i; --M; }
else elist[i].assign(u,v,wa,wb);
}
}
void init()
{
elist[].weightB=-inf;
std::sort(elist+,elist+M+);
;i<=M;i++) node[i].init(i);
;i<=N;i++) node[i+M].init();
;i<=N;i++) center[i]=i;
}
void addEdge(int e)
{
int& u=elist[e].u;
int& v=elist[e].v;
int cu=getCenter(u);
int cv=getCenter(v);
if(cu!=cv)
{
link(e,M+u);
link(e,M+v);
center[cu]=cv;
}
else {
int mx=query(M+u,M+v);
if(elist[e].weightB < elist[mx].weightB)
{
cut(mx,M+elist[mx].u);
cut(mx,M+elist[mx].v);
link(e,M+u);
link(e,M+v);
}
}
}
int solve()
{
int ans(inf);
init();
;i<=M;i++)
{
addEdge(i);
)==getCenter(N))
{
,M+N);
ans=std::min(ans,elist[i].weightA+elist[mx].weightB);
}
}
:ans;
}
int main()
{
input();
printf("%d\n",solve());
;
}
——————分割线——————
这道题我Debug了2天共计5h,最后偶然间查明了死因居然是——
#ifdef WRONG_SPLAY_CODE
void Splay::splay()
{
reverse();
while(!isRoot())
{
);
]) st|=;
;
if(!parent->isRoot())
{
]) st|=;
;
}
switch(st)
{
: rotate(); break;
: rotate(); break;
: parent->rotate(); ); break;
: rotate(); rotate(); break;
: rotate(); rotate(); break;
:parent->rotate(); ); break;
}
}
}
#endif
I FELL COLLAPSED BECAUSE OF THIS
不过在Debug期间,参考了不少其他神犇的AC代码,也学到了各种姿势,算是因祸得福吧……
Vijos1865 NOI2014 魔法森林 LCT维护生成树的更多相关文章
- P2387 [NOI2014]魔法森林 LCT维护最小生成树
\(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...
- 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树
这道题看题意是在求一个二维最小瓶颈路,唯一可行方案就是枚举一维在这一维满足的条件下使另一维最小,那么我们就把第一维排序利用A小的边在A大的情况下仍成立来动态加边维护最小生成树. #include &l ...
- [Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)
题面 传送门:https://www.luogu.org/problemnew/show/P2387 Solution 这题的思想挺好的. 对于这种最大值最小类的问题,很自然的可以想到二分答案.很不幸 ...
- BZOJ 3669: [Noi2014]魔法森林( LCT )
排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...
- bzoj 3669: [Noi2014]魔法森林 (LCT)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec ...
- [NOI2014]魔法森林 LCT
题面 [NOI2014]魔法森林 题解 一条路径的代价为路径上的\(max(a[i]) + max(b[i])\),因为一条边同时有$a[i], b[i]$2种权值,直接处理不好同时兼顾到,所以我们考 ...
- bzoj3669: [Noi2014]魔法森林 lct版
先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...
- loj2245 [NOI2014]魔法森林 LCT
[NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...
- bzoj 3669: [Noi2014] 魔法森林 LCT版
Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...
随机推荐
- BZOJ2083: [Poi2010]Intelligence test
2083: [Poi2010]Intelligence test Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 241 Solved: 96[Sub ...
- luoguP2267 琪琪的项链
题目:http://www.luogu.org/problem/show?pid=2267 题解:这题略吊. 看了之后发现不能用组合数学直接得出公式,然后如果直接暴力也不知道如何去排除两个颜色序列相同 ...
- (转载)MySQL BETWEEN 用法
(转载)http://www.5idev.com/p-php_mysql_between.shtml MySQL BETWEEN 语法 BETWEEN 运算符用于 WHERE 表达式中,选取介于两个值 ...
- 如何将Java源代码文件的编码从GBK转为UTF-8?
有时候看到有意思的demo,在头痛导入项目的编码和workspace的编码不一样的时候 我试着将 笔记本打开一个类一个类的复制, demo的类比较少的时候 可以忍受,demo的类多的时候 除了靠之外 ...
- Delphi 用Web App Debugger简单调试ISAPI 转
用Web App Debugger简单调试ISAPI 以isapi为例: 1.新建一个project,用isapi/nsapi: 2.remove这个project中所有的unit: 3.加进你用 ...
- codeforce --- 340D
D. Bubble Sort Graph time limit per test 1 second memory limit per test 256 megabytes input standard ...
- MySQL安装没有弹出配置向导
安装MySQL过程中一切都正常只是没有弹出MySQL配置向导对话框,即出现"launch the MySQL Instance Configuration Wizard" fini ...
- maya绝招(41--60)
第41招 捕捉和旋转 从MAYA5开始,双击工具箱中的移动缩放旋转工具,马上就可以调出工具属性栏.以旋转为例,将Snap Rotate勾选,并设置Step Size数值,就可以旋转特定的数值了 第42 ...
- Android Studio下载及离线升级方法
由于众所周知的原因,android官网无法访问,所以我们要用到翻.墙.工具,我用的是自.由.门,大家自行搜索下载. android studio下载地址: https://dl.google.com/ ...
- ios策略模式应用
策略模式应用大量应用于解决巨型switch-case if-else..... 具体使用方法 : 策略基类(BaseStrategy)包含一个虚算法,所有子类实现虚算法 容器类含有一个指向策略基类的 ...