传送门1
传送门2
写在前面:我要种树!!
思路:
SPFA:理论复杂度很蛋疼,但实际效果不错,按a排序(b也可以)后从小到大枚举每条边,dis数组不必清空,每次往队列里扔进当前边的两个端点进行拓展,ans=min(ans,dis[n]+v[i]),v[i]指当前边i的a,dis[n]记录的是1-n路径上最大的b,每次扩展走的路径必须是之前已经枚举过的边,这样才能保证1-n路径上的a的最大值不大于当前边i的a
注意自环
代码:
#include<bits/stdc++.h>
using namespace std;
int tot=1,n,m,ans=0x7fffffff;
int first[50010],dis[50010];
struct edge
{
int u,v,A,B,next;
}e[200010];
struct os
{
int id,x;
bool operator <(const os other)const
{
return x<other.x;
}
}qu[100010];
bool flag[200010],vis[50010]; //flag记录之前枚举过的边,vis判断点是否在队列中
queue<int> q;
void add(int x,int y,int a,int b)
{
e[++tot].u=x;
e[tot].v=y;
e[tot].A=a;
e[tot].B=b;
e[tot].next=first[x];
first[x]=tot;
}
main()
{
int a,b,c,d,k;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d%d%d%d",&a,&b,&c,&d),
add(a,b,c,d),
qu[i].id=tot,
qu[i].x=c,
add(b,a,c,d);
sort(qu+1,qu+m+1);
memset(dis,63,sizeof(dis));
dis[1]=0;
if (n==1) printf("0"),exit(0);
for (int i=1;i<=m;i++)
{
int now=qu[i].id;
flag[now]=flag[now^1]=1;
if (!vis[e[now].v]) q.push(e[now].v),vis[e[now].v]=1;
if (!vis[e[now].u]) q.push(e[now].u),vis[e[now].u]=1;
while (!q.empty())
{
k=q.front();
q.pop();
for (int j=first[k];j;j=e[j].next)
if (flag[j]&&dis[e[j].v]>max(dis[k],e[j].B))
{
dis[e[j].v]=max(dis[k],e[j].B);
if (!vis[e[j].v]) vis[e[j].v]=1,q.push(e[j].v);
}
vis[k]=0;
}
if (dis[n]>1000000) continue;
ans=min(ans,dis[n]+qu[i].x);
}
if (ans>1000000) printf("-1");
else printf("%d",ans);
}
LCT:并查集维护点之间的连通性,在LCT中把每条边缩成带有权值的节点,而每个点没有权值,与它的边在LCT中对应的节点相连。同样的按a升序排一遍,每次枚举边i(端点为u,v),如果u,v不连通就link一下,联通就的话就找出u-v路径上的最大权值点j(就是b权值最大的边),如果val[j]<=val[i],那么在有j时走i一定不会更优;若val[j]>val[i]决策不定,但我们也可以cut掉j,把ilink上,因为我们每次枚举边时都会求下1-n的答案,留下i可能会更新答案,而且由于形成一个环,j的存在也不会影响答案,但它影响了LCT的结构,所以把它删去
注意:BZOJ上要把数组开大一点,不然codevs上A的程序在那上面可能会RE
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,ans=0x7fffffff;
int stacks[400010],father[400010];
struct edge
{
int u,v,A,B;
bool operator <(const edge other)const
{
return A<other.A;
}
}e[400010];
struct tree
{
int fa,ch[2],lazy,data,maxn;
}a[400010];
int find(int x)
{
if (father[x]!=x) father[x]=find(father[x]);
return father[x];
}
void ct(int x)
{
int l=a[x].ch[0],r=a[x].ch[1];
a[x].maxn=(a[a[l].maxn].data>a[a[r].maxn].data?a[l].maxn:a[r].maxn);
a[x].maxn=(a[a[x].maxn].data>a[x].data?a[x].maxn:x);
}
void pushdown(int x)
{
if (!a[x].lazy) return;
a[a[x].ch[0]].lazy^=1;
a[a[x].ch[1]].lazy^=1;
swap(a[x].ch[0],a[x].ch[1]);
a[x].lazy=0;
}
bool isroot(int x)
{
return a[a[x].fa].ch[0]!=x&&a[a[x].fa].ch[1]!=x;
}
void rorate(int x,bool mk)
{
int y=a[x].fa;
a[x].fa=a[y].fa;
if (!isroot(y))
{
if (a[a[y].fa].ch[0]==y) a[a[y].fa].ch[0]=x;
else a[a[y].fa].ch[1]=x;
}
a[y].ch[!mk]=a[x].ch[mk];
a[a[x].ch[mk]].fa=y;
a[y].fa=x;
a[x].ch[mk]=y;
ct(y);
ct(x);
}
void splay(int x)
{
int y,cnt=0,k=x;
stacks[++cnt]=k;
while (!isroot(k)) k=a[k].fa,stacks[++cnt]=k;
for (int i=cnt;i;i--) pushdown(stacks[i]);
while (!isroot(x))
{
y=a[x].fa;
if (isroot(y))
{
int t=a[y].fa;
if (a[y].ch[0]==x) rorate(x,1);
else rorate(x,0);
a[x].fa=t;
}
else if (a[a[y].fa].ch[0]==y)
{
if (a[y].ch[0]==x) rorate(y,1);
else rorate(x,0);
rorate(x,1);
}
else
{
if (a[y].ch[1]==x) rorate(y,0);
else rorate(x,1);
rorate(x,0);
}
}
}
void access(int x)
{
for (int y=0;x;y=x,x=a[x].fa)
splay(x),
a[x].ch[1]=y,
ct(x);
}
void link(int x,int y)
{
access(x);
splay(x);
a[x].lazy^=1;
a[x].fa=y;
splay(x);
}
void cut(int x,int y)
{
access(x);
splay(x);
a[x].lazy^=1;
access(y);
splay(y);
a[x].fa=a[y].ch[0]=0;
ct(y);
}
int ask(int x,int y)
{
access(x);
splay(x);
a[x].lazy^=1;
access(y);
splay(y);
return a[y].maxn;
}
main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) father[i]=i;
for (int i=1;i<=m;i++)
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].A,&e[i].B);
sort(e+1,e+m+1);
for (int i=1;i<=m;i++)
{
int p=find(e[i].u),q=find(e[i].v);
a[n+i].data=e[i].B;
a[n+i].maxn=n+i;
if (p!=q) father[p]=q,link(e[i].u,n+i),
link(e[i].v,n+i);
else
{
int t=ask(e[i].u,e[i].v);
if (e[t-n].B>e[i].B)
{
cut(e[t-n].u,t);
cut(e[t-n].v,t);
link(e[i].u,i+n);
link(e[i].v,i+n);
}
}
if (find(1)==find(n)) ans=min(ans,e[i].A+a[ask(1,n)].data);
}
if (ans>1000000) printf("-1");
else printf("%d",ans);
}
……
……
……
为什么两个程序一加快速读入就会出问题啊(┬_┬)