您的位置:首页 > 其它

3669 [Noi2014]魔法森林(LCT,最小生成树)

2016-03-27 19:12 309 查看
【题目链接】

http://www.lydsy.com/JudgeOnline/problem.php?id=3669

【题意】

给定一个无向图,求1-n的路径中最小的max{ai}+max{bi}

【思路】

将边按照a排序。LCT维护关于b的最小生成树。

顺序枚举每条边u,v,如果u,v已经连接则比较u,v路径上的最大边与新边,否则直接相连。

如果1与n连通,则用e.a+max{e.b}更新ans。直观地看,最小生成树上的max{e.b}是1..i条边加入后能够得到的最小b。

_max的初值赋-1,即保证maxe存在,否则无限TLE

【代码】

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;

typedef long long ll;
const int N = 1e5+10;

ll read() {
char c=getchar();
ll f=1,x=0;
while(!isdigit(c)) {
if(c=='-') f=-1; c=getchar();
}
while(isdigit(c))
x=x*10+c-'0',c=getchar();
return x*f;
}

struct Edge {
int u,v,a,b;
bool operator < (const Edge& rhs) const {
return a<rhs.a;
}
}e[N<<1];
int en;
void adde(int u,int v,int a,int b)
{
e[++en]=(Edge){u,v,a,b};
}

namespace LCT {

struct Node {
int rev,v,maxe;
Node *ch[2],*fa;
Node() {}
Node(int x) ;
void reverse() {
rev^=1;
swap(ch[0],ch[1]);
}
void up_push() {
if(fa->ch[0]==this||fa->ch[1]==this)
fa->up_push();
if(rev) {
ch[0]->reverse();
ch[1]->reverse();
rev=0;
}
}
void maintain() {
int _max=-1;
if(e[ch[0]->maxe].b>_max)
_max=e[ch[0]->maxe].b,maxe=ch[0]->maxe;
if(e[ch[1]->maxe].b>_max)
_max=e[ch[1]->maxe].b,maxe=ch[1]->maxe;
if(e[v].b>_max) maxe=v;
}
} T[N<<1],E[N<<1],*null=&T[0];
Node::Node(int x) {
ch[0]=ch[1]=fa=null;
rev=0; v=maxe=x;
}

void rot(Node* o,int d) {
Node *p=o->fa;
p->ch[d]=o->ch[d^1];
o->ch[d^1]->fa=p;
o->ch[d^1]=p;
o->fa=p->fa;
if(p==p->fa->ch[0])
p->fa->ch[0]=o;
else if(p==p->fa->ch[1])
p->fa->ch[1]=o;
p->fa=o;
p->maintain();
}
void splay(Node* o) {
o->up_push();
Node* nf,*nff;
while(o->fa->ch[0]==o||o->fa->ch[1]==o) {
nf=o->fa,nff=nf->fa;
if(o==nf->ch[0]) {
if(nf==nff->ch[0]) rot(nf,0);
rot(o,0);
} else {
if(nf==nff->ch[1]) rot(nf,1);
rot(o,1);
}
}
o->maintain();
}
void Access(Node *o) {
Node *son=null;
while(o!=null) {
splay(o);
o->ch[1]=son;
o->maintain();
son=o; o=o->fa;
}
}
void evert(Node *o) {
Access(o);
splay(o);
o->reverse();
}
void Link(Node *u,Node *v) {
evert(u);
u->fa=v;
}
void Cut(Node *u,Node *v) {
evert(u);
Access(v),splay(v);
v->ch[0]=u->fa=null;
v->maintain();
}
Node *find(Node *o) {
while(o->fa!=null) o=o->fa;
return o;
}

}
using namespace LCT ;

int n,m;

int query(Node *u,Node* v)
{
evert(u);
Access(v),splay(v);
return v->maxe;
}

int main()
{
//    freopen("in.in","r",stdin);
//    freopen("out.out","w",stdout);
n=read(),m=read();
int u,v,a,b;
FOR(i,1,m) {
u=read(),v=read(),a=read(),b=read();
adde(u,v,a,b);
}
FOR(i,1,m) E[i]=Node(i);
FOR(i,1,n) T[i]=Node(0);
sort(e+1,e+m+1);
int ans=1e9;
FOR(i,1,m) {
int u=e[i].u,v=e[i].v;
if(find(&T[u])==find(&T[v])) {
int maxe=query(&T[u],&T[v]);
if(e[i].b>=e[maxe].b) continue;
Cut(&E[maxe],&T[e[maxe].u]);
Cut(&E[maxe],&T[e[maxe].v]);
}
Link(&T[u],&E[i]);
Link(&T[v],&E[i]);
if(find(&T[1])==find(&T
)) {
int maxe=query(&T[1],&T
);
if(e[maxe].b+e[i].a<ans) ans=e[maxe].b+e[i].a;
}
}
if(ans==1e9) puts("-1");
else printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: