您的位置:首页 > 其它

[bzoj 2725] 故乡的梦

2016-02-04 16:19 375 查看
丧病图论题……

这是个权限题……所以不放传送门了,说一下题目大意。

给定一个n个点,m条边的无向图,一个S,一个T,有Q个询问,每次询问删掉某条边之后S到T的最短路。(n,m,q<=200000)

先从S跑一遍最短路,再从T跑一遍最短路。然后我们考虑一个简化的问题:求删掉某条边之后S到T的最短路是否会变化。

可以看出,满足disS[u]+w(u,v)+disT[v]==disS[T]的边(u,v)一定在S到T的最短路上。我们把所有这样的边弄出来,跑一遍tarjan,那么当且仅当它是桥时S到T的最短路会变化。

这给我们提供了思路。于是,可以将这些tarjan跑出来的双连通分量缩起来。显然,这些双连通分量从S到T构成一条链,将它由S到T的顺序编号。

考虑删掉桥之后的答案,显然是用某一条非最短路上的边(u,v)代替,距离变成disS[u]+w(u,v)+disT[v]。

再考虑每条边可以代替哪些桥。

必须满足一下几个条件:

假设当前这座桥连接i到i+1的连通分量,当前边为(u,v)

1.可以用前i块连通分量的点走到u,且保证是S到u的最短路

2.可以用i之后连通分量的点走到v,且保证是T到v的最短路

于是,我们再跑两棵最短路树,一棵起点为S,另外一棵起点为T,然后给每个点一个belong1[i],一个belong2[i],即从哪个连通分量可以走S到i的最短路到i,从哪个连通分量可以走T到i的最短路到i。然而这样的连通分量可能有很多个,对于belong1,我们选编号最小的;对于belong2,我们选编号最大的。

我们从S到T的每个双连通分量扫描,每扫描到一块,加入这个连通分量到后面的边,删除前面的连通分量到它的边。用一个堆维护,关键字是disS[u]+w(u,v)+disT[v]。起点的连通分量为belong1[i],终点为belong2[i]。

啥都不说上代码。写得快哭了,用map还被卡常了……。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <deque>
#include <queue>
#include <map>
#include <set>
#include <ctime>
using namespace std;

typedef long long ll;
const int Maxn=200005;
const ll INF=ll(1)<<ll(60);

vector<int> bcc[Maxn];
int belong[Maxn],tt;

struct node
{
int x;ll val;
node(){} node(int _x,ll _val) { x=_x,val=_val; }
};

bool operator < (const node &a,const node &b) { return a.val>b.val; }
priority_queue<node> H;

struct Edge
{
int from,to,cost;bool flag;
}E[Maxn<<1];
bool cmp(const Edge &a,const Edge &b) { return belong[a.from]<belong[b.from]; }

int Get()
{
char ch; int v=0; bool f=false;
while (!isdigit(ch=getchar())) if (ch=='-') f=true; v=ch-48;
while (isdigit(ch=getchar())) v=v*10+ch-48;
if (f) return -v;else return v;
}

void Put(ll x)
{
char ch[21]; int tot=0;
if (x==0) { puts("0");return; }
while (x) ch[++tot]=x%10,x/=10;
for (;tot;tot--) putchar(ch[tot]+48);puts("");
}

int n,m,q,tot,S,T,fst[Maxn],pre[Maxn<<1],to[Maxn<<1],from[Maxn<<1],cost[Maxn<<1],head,tail,Q[Maxn],
dfs_clock,dfn[Maxn],low[Maxn],col[Maxn],bridge[Maxn],belong2[Maxn];
ll disS[Maxn],disT[Maxn],ans[Maxn<<1];
bool vis[Maxn],flag[Maxn<<1],imp[Maxn<<1],imp2[Maxn<<1],is_bridge[Maxn<<1];

void add(int x,int y,int c)
{
if (x==y) return;
pre[++tot]=fst[x],fst[x]=tot,from[tot]=x,to[tot]=y,cost[tot]=c;
E[tot].from=x,E[tot].to=y,E[tot].cost=c,E[tot].flag=false;
pre[++tot]=fst[y],fst[y]=tot,from[tot]=y,to[tot]=x,cost[tot]=c;
E[tot].from=y,E[tot].to=x,E[tot].cost=c,E[tot].flag=false;
}

void Dijkstra(int S,ll *dis)
{
while (!H.empty()) H.pop();
for (int i=1;i<=n;i++) vis[i]=false,dis[i]=INF;
dis[S]=0; H.push(node(S,0)); vis[S]=true;
while (!H.empty())
{
node cur=H.top(); H.pop();
int x=cur.x;
if (cur.val!=dis[x]) continue;
for (int i=fst[x];i;i=pre[i])
{
int y=to[i];
if (!vis[y] && dis[x]+ll(cost[i])<dis[y]) dis[y]=dis[x]+ll(cost[i]),H.push(node(y,dis[y]));
}
vis[x]=true;
}
}

void tarjan(int x,int prev)
{
vis[x]=true; dfn[x]=low[x]=++dfs_clock;
for (int i=fst[x];i;i=pre[i])
{
int y=to[i];
if (i==(prev^1) || !flag[i]) continue;
if (!vis[y]) tarjan(y,i),low[x]=min(low[x],low[y]);
else low[x]=min(low[x],dfn[y]);
}
if (dfn[x]==low[x]) is_bridge[prev]=is_bridge[prev^1]=true;
}

void dfs(int x)
{
belong[x]=tot,vis[x]=true; bcc[tot].push_back(x);
for (int i=fst[x];i;i=pre[i])
{
int y=to[i];
if (!vis[y] && !is_bridge[i] && flag[i]) dfs(y);
}
}

void getchain()
{
for (int i=1;i<=tot;i++) vis[i]=false;
int cur=belong[S],cnt=0;
while (cur!=belong[T])
{
col[cur]=++cnt;vis[cur]=true;
int len=bcc[cur].size(); bool ff=false;
for (int i=0;i<len && !ff;i++)
{
int x=bcc[cur][i];
for (int j=fst[x];j && !ff;j=pre[j])
if (is_bridge[j] && !vis[belong[to[j]]]) { bridge[cnt]=j; cur=belong[to[j]]; ff=true; }
}
}
col[cur]=++cnt;
for (int i=1;i<=n;i++) belong[i]=col[belong[i]],belong2[i]=belong[i];
for (int i=1;i<=tot;i++) while (!bcc[i].empty()) bcc[i].pop_back();
tot=cnt;
for (int i=1;i<=n;i++) bcc[belong[i]].push_back(i);
}

void bfs1(int cur)
{
head=tail=1; int len=bcc[cur].size();
for (int i=0;i<len;i++) Q[tail++]=bcc[cur][i],vis[bcc[cur][i]]=true;
while (head!=tail)
{
int x=Q[head++];
for (int i=fst[x];i;i=pre[i])
{
int y=to[i];
if (!vis[y] && imp[i]) Q[tail++]=y,belong[y]=cur,vis[y]=true;
}
}
}

void bfs2(int cur)
{
head=tail=1; int len=bcc[cur].size();
for (int i=0;i<len;i++) Q[tail++]=bcc[cur][i],vis[bcc[cur][i]]=true;
while (head!=tail)
{
int x=Q[head++];
for (int i=fst[x];i;i=pre[i])
{
int y=to[i];
if (!vis[y] && imp2[i]) Q[tail++]=y,belong2[y]=cur,vis[y]=true;
}
}
}

void init()
{
n=Get(),m=Get(); int x,y,c; tot=1;
for (int i=1;i<=m;i++) x=Get(),y=Get(),c=Get(),add(x,y,c);
S=Get(),T=Get(); tt=tot;
Dijkstra(S,disS); Dijkstra(T,disT);
if (disS[T]==INF)
{
q=Get();
while (q--) x=Get(),y=Get(),puts("Infinity");
return;
}

for (int i=2;i<=tot;i+=2)
{
if (disS[from[i]]+ll(cost[i])+disT[to[i]]==disS[T] || disS[to[i]]+ll(cost[i])+disT[from[i]]==disS[T])
flag[i]=flag[i^1]=true,E[i].flag=E[i^1].flag=true;
else
{
if (disS[from[i]]+ll(cost[i])==disS[to[i]]) imp[i]=true;
if (disT[from[i]]+ll(cost[i])==disT[to[i]]) imp2[i]=true;
if (disS[to[i]]+ll(cost[i])==disS[from[i]]) imp[i^1]=true;
if (disT[to[i]]+ll(cost[i])==disT[from[i]]) imp2[i^1]=true;
}
}
for (int i=1;i<=n;i++) vis[i]=false;
dfs_clock=0; tarjan(S,0);
for (int i=1;i<=n;i++) vis[i]=false;
tot=0; for (int i=1;i<=n;i++) if (!vis[i]) tot++,dfs(i);
getchain();
for (int i=1;i<=n;i++) vis[i]=false;
for (int i=1;i<=tot;i++) bfs1(i);

for (int i=1;i<=n;i++) vis[i]=false;
for (int i=tot;i>=1;i--) bfs2(i);
}

void work()
{
if (disS[T]==INF) return;
while (!H.empty()) H.pop();
sort(E+2,E+tt+1,cmp);
for (int i=1,j=2;i<=tot-1;i++)
{
for (;j<=tt && belong[E[j].from]==i;j++)
if (!E[j].flag) H.push(node(E[j].to,disS[E[j].from]+ll(E[j].cost)+disT[E[j].to]));
while (!H.empty() && belong2[H.top().x]<=i) H.pop();
if (!H.empty()) ans[bridge[i]]=ans[bridge[i]^1]=H.top().val;
else ans[bridge[i]]=ans[bridge[i]^1]=INF;
}
for (int i=2;i<=tt;i++) if (!is_bridge[i]) ans[i]=disS[T];

q=Get(); int x,y;
while (q--)
{
x=Get(),y=Get(); ll res; int pos;
for (int i=fst[x];i;i=pre[i]) if (to[i]==y) { pos=i;break; }
if (x!=y) res=ans[pos];else res=disS[T];
if (res!=INF) Put(res);else puts("Infinity");
}
}

int main()
{
// freopen("hometown.in","r",stdin);
// freopen("hometown.out","w",stdout);
init();
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: