NOI 2014魔法森林

        解法大致同BZOJ2594

        首先先将a排序,逐边加入,每次维护一条链上最大的b,再次加入时,如果没有连通则直接链上,否则必定会生成环,那么就将b最大的删去即可

#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXN = 50001;
const int MAXM = 100001; 
const int INF = 1000001;

void READ(int &x)
{
	x = 0;
	char c;
	do c = getchar();while (c > '9' || c < '0');
	do x = x*10+c-48, c = getchar(); while (c <= '9' && c >= '0'); 
};

struct Edge
{
	int u,v,a,b;
};

Edge Edges[MAXM];

int n,m;
int f[MAXN];

bool cmpa(Edge A,Edge B)
{
	return A.a < B.a;
}

struct Node *null;
struct Node
{
	int id;
	Node *ch[2],*f;
	int vA,vB;
	int maxA,maxB,maxBlocal;
	int size;
	bool rev;
	void maintain()
	{
		size = 1+ch[0]->size+ch[1]->size;
		maxB = vB, maxBlocal = id;
		if (ch[0]->maxB > maxB) maxB = ch[0]->maxB, maxBlocal = ch[0]->maxBlocal;
		if (ch[1]->maxB > maxB) maxB = ch[1]->maxB, maxBlocal = ch[1]->maxBlocal;
		maxA = max(vA,ch[0]->maxA), maxA = max(maxA,ch[1]->maxA);
	}
	void pushdown()
	{
		if (rev)
		{
			rev ^= 1;
			ch[0]->rev ^= 1, ch[1]->rev ^= 1;
			swap(ch[0],ch[1]);
		}
	}
	void setc(Node *c,int d){ch[d] = c, c->f = this;}
	bool check(){return f != null && (f->ch[0] == this || f->ch[1] == this);}
	int d(){return f->ch[1] == this ? 1 : 0;}
	Node (int _id,int _vA,int _vB):id(_id),vA(_vA),vB(_vB){ch[0] = ch[1] = f = null, rev = false, maintain();}
	Node (){ch[0] = ch[1] = NULL, rev = false, size = 0, maxA = maxB = -INF;}
};

Node *p[MAXN+MAXM];

void rotate(Node *p)
{
	Node *x = p->f;
	x->pushdown();p->pushdown();
	int d = p->d();
	if (!x->check()) p->f = x->f;
	else x->f->setc(p,x->d());
	x->setc(p->ch[d^1],d);
	p->setc(x,d^1);
	x->maintain(); 
}

void Splay(Node *p)
{
	p->pushdown();
	while (p->check())
	{
		Node *x = p->f;
		if (!x->check()) rotate(p);
		else x->d() == p->d() ? (rotate(x),rotate(p)) : (rotate(p),rotate(p));
	}
	p->maintain();
}

void Access(Node *p)
{
	for (Node *q = null; p != null; p = p->f)
	{
		Splay(p);
		p->setc(q,1);
		(q = p)->maintain();
	}
}

inline void MakeRoot(Node *p)
{
	Access(p);Splay(p);p->rev ^= 1;
}

void Link(Node *p,Node *q)
{
	MakeRoot(p);p->f = q;
}

void Cut(Node *p,Node *q)
{
	MakeRoot(p);
	Access(q);Splay(q);
	p->f = q->ch[0] = null;
	q->maintain();
}

Node* Query(Node *p,Node *q)
{
	MakeRoot(p);
	Access(q);Splay(q);
	return q;
}

int find(int x)
{
	return x == f[x] ? f[x] : f[x] = find(f[x]);
}

int main()
{
	null = new Node();
	READ(n);READ(m);
	for (int i=1;i<=m;i++) READ(Edges[i].u),READ(Edges[i].v),READ(Edges[i].a),READ(Edges[i].b);
	sort(Edges+1,Edges+m+1,cmpa);
	for (int i=1;i<=n;i++) f[i] = i;
	for (int i=1;i<=n+m;i++) p[i] = new Node(i,0,0);
	int ans = INF;
	for (int i=1;i<=m;i++)
	{
		int Su = find(Edges[i].u);
		int Sv = find(Edges[i].v);
		Node *temp;
		if (Su != Sv) 
		{
			f[Su] = Sv;
			p[i+n]->vA = Edges[i].a, p[i+n]->vB = Edges[i].b;
			Link(p[Edges[i].u],p[i+n]);Link(p[Edges[i].v],p[i+n]);
		}
		else
		{
			temp = Query(p[Edges[i].u],p[Edges[i].v]);
			if (Edges[i].b < temp->maxB)
			{
				int point = temp->maxBlocal-n;
				Cut(p[point+n],p[Edges[point].u]);Cut(p[point+n],p[Edges[point].v]);
				p[i+n] = new Node(i+n,Edges[i].a,Edges[i].b);
				Link(p[i+n],p[Edges[i].u]);Link(p[i+n],p[Edges[i].v]);
			}
		}
		if (find(1) == find(n)) temp = Query(p[1],p[n]), ans = min(ans,temp->maxA+temp->maxB);	
	}
	if (find(1) != find(n))
	{
		puts("-1");
		return 0;
	}
	printf("%d\n",ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值