[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;
}