luogu2387 [NOI2014]魔法森林

link

显然满足的条件是一个偏序关系

我们把所有边权按照a排序,按a从小到大顺序加边

然后我们发现b上的问题就是一个动态最小瓶颈生成树问题,刚好可以用动态树维护

代码暂时还没写

upd:代码写完了

第一次写的时候tmd nroot写错了。。。

#include <cstdio>
#include <algorithm>
using namespace std;

int n, m;
int ch[150010][2], fa[150010], st[150010], pos[150010], val[150010];
bool lazy[150010];
int u[150010], v[150010];
struct edge { int x, y, a, b; } a[100010];

void chkmin(int &a, int b) { if (a > b) a = b; }
int ans = 0x3f3f3f3f, tot;

bool nroot(int x) { return ch[fa[x]][1] == x || ch[fa[x]][0] == x; }
void rev(int x) { swap(ch[x][0], ch[x][1]), lazy[x] ^= 1; }

void pushup(int x)
{
	if (val[pos[ch[x][0]]] < val[pos[ch[x][1]]]) pos[x] = pos[ch[x][1]];
	else pos[x] = pos[ch[x][0]];
	if (val[x] > val[pos[x]]) pos[x] = x;
}

void pushdown(int x)
{
	if (lazy[x] == 1)
	{
		if (ch[x][0]) rev(ch[x][0]);
		if (ch[x][1]) rev(ch[x][1]);
		lazy[x] = 0;
	}
}

void rotate(int x)
{
	int y = fa[x], z = fa[y];
	int k = ch[y][1] == x, w = ch[x][k ^ 1];
	if (nroot(y)) ch[z][ch[z][1] == y] = x;
	ch[x][k ^ 1] = y, ch[y][k] = w;
	if (w) fa[w] = y;
	fa[y] = x, fa[x] = z;
	pushup(y), pushup(x);
}

void splay(int x)
{
	int y = x, top = 0;
	st[++top] = y;
	while (nroot(y)) st[++top] = y = fa[y];
	while (top > 0) pushdown(st[top--]);
	while (nroot(x))
	{
		int y = fa[x], z = fa[y];
		if (nroot(y)) rotate((ch[y][1] == x) ^ (ch[z][1] == y) ? x : y);
		rotate(x);
	}
	pushup(x);
}

void access(int x)
{
	for (int y = 0; x > 0; x = fa[y = x])
		splay(x), ch[x][1] = y, pushup(x);
}

void makeroot(int x)
{
	access(x), splay(x), rev(x);
}

int findroot(int x)
{
	access(x), splay(x);
	while (ch[x][0])
		pushdown(x), x = ch[x][0];
	return x;
}

void split(int x, int y)
{
	makeroot(x), access(y), splay(y);
}

void link(int x, int y)
{
	makeroot(x);
	if (findroot(y) != x) fa[x] = y;
}

void cut(int x, int y)
{
	makeroot(x);
	if (findroot(y) == x && fa[x] == y && ch[x][1] == 0)
		ch[y][0] = fa[x] = 0, pushup(y);
}

int main()
{
	scanf("%d%d", &n, &m); tot = n;
	for (int i = 1; i <= m; i++) scanf("%d%d%d%d", &a[i].x, &a[i].y, &a[i].a, &a[i].b);
	sort(a + 1, a + 1 + m, [](const edge &a, const edge &b) { return a.a < b.a; });
	for (int i = 1; i <= m; i++)
	{
		makeroot(a[i].x);
		if (findroot(a[i].y) == a[i].x)
		{
			if (val[pos[a[i].y]] > a[i].b)
			{
				int p = pos[a[i].y];
				cut(p, u[p]);
				cut(p, v[p]);
				p = ++tot;
				u[p] = a[i].x;
				v[p] = a[i].y;
				val[p] = a[i].b;
				pos[p] = p;
				link(p, u[p]);
				link(p, v[p]);
			}
		}
		else
		{
			int p = ++tot;
			u[p] = a[i].x;
			v[p] = a[i].y;
			val[p] = a[i].b;
			pos[p] = p;
			link(p, u[p]);
			link(p, v[p]);
		}
		makeroot(1);
		if (findroot(n) == 1)
			chkmin(ans, val[pos[n]] + a[i].a);
	}
	printf("%d\n", ans == 0x3f3f3f3f ? -1 : ans);
	return 0;
}
posted @ 2019-02-15 21:08  ghj1222  阅读(154)  评论(0编辑  收藏  举报