[NOI 2014]魔法森林

题意:求带修最短路。

思路:一开始想的就是LCT维护一棵最小生成树,后来发现还有动态开点SPFA的这种操作...神了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N=300010;

int ch[N][2],pre[N],v[N],pos[N],fa[N];

bool rev[N];

int Q[N],n,m;

struct node
{
	int x,y,a,b;
}po[N];


int cmp(const node &A,const node &B) {
	if (A.a!=B.a) return A.a<B.a;
	else return A.b<B.b;
}

int get(int num) {
	return ch[pre[num]][0]==num? 0:1;
}

int isroot(int num) { 
	return ch[pre[num]][0]!=num&&ch[pre[num]][1]!=num;
}

void update(int num) {
	if (!num) return;
	pos[num]=num;
	int l=ch[num][0];
	int r=ch[num][1];
	if (l&&v[pos[l]]>v[pos[num]]) pos[num]=pos[l];
	if (r&&v[pos[r]]>v[pos[num]]) pos[num]=pos[r];
}

void push(int num) {
	if (!num) return;
	if (rev[num]) {
		if (ch[num][0]) rev[ch[num][0]]^=1;
		if (ch[num][1]) rev[ch[num][1]]^=1;
		swap(ch[num][0],ch[num][1]);
		rev[num]^=1;
	}
}

void rotate(int num) {
	int fa=pre[num];
	int grand=pre[fa];
	int wh=get(num);
	if (!isroot(fa)) ch[grand][ch[grand][0]==fa? 0:1]=num;
	pre[num]=grand;
	ch[fa][wh]=ch[num][wh^1];
	pre[ch[fa][wh]]=fa;
	ch[num][wh^1]=fa;
	pre[fa]=num;
	update(fa);
	update(num);
}

void splay(int num) {
	int top=0;
	Q[++top]=num;
	for (int i=num; !isroot(i); i=pre[i])
		Q[++top]=pre[i];
	while (top) push(Q[top--]);
	for (int fa; !isroot(num); rotate(num))
		if (!isroot(fa=pre[num]))
			rotate(get(num)==get(fa)? fa:num);
}

void expose(int num) {
	int t=0;
	while (num) {
		splay(num);
		ch[num][1]=t;
		update(num);
		t=num;
		num=pre[num];
	}
}

void makeroot(int num) {
	expose(num);
	splay(num);
	rev[num]^=1;
}

void link(int x,int y) {
	makeroot(x);
	pre[x]=y;
}

void cut(int x,int y) {
	makeroot(x);
	expose(y);
	splay(y);
	ch[y][0]=pre[x]=0;
}

int way(int x,int y) {
	makeroot(x);
	expose(y);
	splay(y);
	return pos[y];
}

int find(int x) {
	if (fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}

int main() {
	scanf("%d%d",&n,&m);
	for (int i=1; i<=m; i++)
		scanf("%d%d%d%d",&po[i].x,&po[i].y,&po[i].a,&po[i].b);

	int ans=1e9;
	sort(po+1,po+1+m,cmp);
	for (int i=1; i<=n; i++) fa[i]=i;
	for (int i=1; i<=m; i++) {
		int f1=find(po[i].x);
		int f2=find(po[i].y);
		if (f1!=f2) {
			fa[f1]=f2;
		} 
		else {
			int p=way(po[i].x,po[i].y);   
			if (v[p]>po[i].b) {
				cut(p,po[p-n].x);
				cut(p,po[p-n].y);
			} else {
				if (find(1)==find(n))
					ans=min(ans,v[way(1,n)]+po[i].a);
				continue;
			}
		}
		v[i+n]=po[i].b;
		pos[i+n]=i+n;
		link(po[i].x,n+i);
		link(po[i].y,n+i);
		if (find(1)==find(n))
		{
			int p=way(1,n);
			ans=min(ans,v[p]+po[i].a);
		}
	}

	if (ans==1e9) 
	  printf("-1");
	else 
	  printf("%d",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/akoasm/p/9419370.html