版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/83113320
Description
给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。
对于100%的数据,N<=10000,Q<=10000
Solution
写到怀疑人生。。
给定的图是一个仙人掌,于是可以愉快地建圆方树。
我们记每个环内dfs序最小的圆点为top,维护top到剩余点的距离记为dis,对环上的圆点做距离的前缀和。数据不大这一步怎么做都可以
我们把圆点到方点父亲的边权设为dis[x],方点到dfs序最小的圆点的边权设为0
由于没有修改,考虑倍增求这个东西。
若询问(x,y)的lca是圆点,那么答案就是路径上dis的和
若询问(x,y)的lca是方点,那么答案下图中x到蓝点和y到红点的dis的和,加上红点到蓝点的距离(感受一下
换上最短路可以记录一个换上的边权之和sum,然后减一下取min就可以了
对拍的时候生成仙人掌的数据可以先生成若干个环,然后把环当成树的节点连成一棵树即可
考虑带修改的版本怎么做。同样建圆方树,对于前缀和要资瓷区间加和单点查询,对于树上路径要资瓷单点修改区间查询,还要改top到其余点的dis。光是想想就觉得难写……
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
const int N=200005;
const int E=500005;
struct Graph {
struct edge {int x,y,w,next;} e[E];
int ls[N],edCnt;
Graph() {
fill(ls,0);
edCnt=1;
}
void add_edge(int x,int y,int w) {
e[++edCnt]=(edge) {x,y,w,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,w,ls[y]}; ls[y]=edCnt;
}
} G,T;
std:: stack <int> stack;
std:: vector <int> scc[N];
std:: set <pair> zhx[N];
int dis[N],dfn[N],low[N],tot;
int size[N],bl[N],dep[N],top[N],sum[N];
int lxf[21][N],fa[21][N],bel[N],n;
bool vis[N],mark[N];
inline int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void spfa(int st) {
std:: queue <int> que; que.push(st);
dis[st]=0;
for (;!que.empty();) {
int now=que.front(); que.pop();
for (int i=G.ls[now];i;i=G.e[i].next) {
if (mark[G.e[i].y]&&dis[now]+G.e[i].w<dis[G.e[i].y]) {
dis[G.e[i].y]=dis[now]+G.e[i].w;
if (!vis[G.e[i].y]) {
vis[G.e[i].y]=true;
que.push(G.e[i].y);
}
}
} vis[now]=false;
}
}
void dfs1(int now,int from) {
dfn[now]=low[now]=++dfn[0]; vis[now]=true;
for (int i=G.ls[now];i;i=G.e[i].next) {
if ((i^1)==from) continue;
if (!dfn[G.e[i].y]) {
stack.push(i);
dfs1(G.e[i].y,i);
low[now]=std:: min(low[now],low[G.e[i].y]);
if (dfn[now]<=low[G.e[i].y]) {
int y=0,fir=0; tot++;
while (y!=i) {
y=stack.top(); stack.pop();
if (!fir) fir=y;
scc[tot].push_back(G.e[y].y);
bel[G.e[y].y]=tot;
sum[tot]+=G.e[y].w; zhx[tot].insert(pair(G.e[y].x,sum[tot]));
}
bel[now]=tot;
for (int j=G.ls[G.e[fir].y];j;j=G.e[j].next) {
if (G.e[j].y==now) {
sum[tot]+=G.e[j].w;
zhx[tot].insert(pair(G.e[j].x,sum[tot]));
}
}
top[tot]=now;
}
} else if (vis[G.e[i].y]) low[now]=std:: min(low[now],dfn[G.e[i].y]);
}
vis[now]=false;
}
void dfs2(int now) {
rep(i,1,20) fa[i][now]=fa[i-1][fa[i-1][now]];
rep(i,1,20) lxf[i][now]=lxf[i-1][now]+lxf[i-1][fa[i-1][now]];
for (int i=T.ls[now];i;i=T.e[i].next) {
if (T.e[i].y==fa[0][now]) continue;
fa[0][T.e[i].y]=now; dep[T.e[i].y]=dep[now]+1;
if (now>=n) lxf[0][T.e[i].y]=dis[T.e[i].y];
// else lxf[0][T.e[i].y]=T.e[i].w;
dfs2(T.e[i].y);
}
}
int solve(int x,int y) {
int ret=0;
if (dep[x]<dep[y]) std:: swap(x,y);
drp(i,20,0) if (dep[fa[i][x]]>=dep[y]) {
ret+=lxf[i][x];
x=fa[i][x];
}
if (x==y) return ret;
drp(i,20,0) if (fa[i][x]!=fa[i][y]) {
ret+=lxf[i][x]+lxf[i][y];
x=fa[i][x],y=fa[i][y];
}
int wjp=lxf[0][x]+lxf[0][y];
if (fa[0][x]<=n) return ret+wjp;
pair chp=*zhx[fa[0][x]].lower_bound(pair(x,0));
pair lyh=*zhx[fa[0][x]].lower_bound(pair(y,0));
wjp=abs(chp.se-lyh.se);
wjp=std:: min(wjp,sum[fa[0][x]]-wjp);
return ret+wjp;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
n=read(); int m=read(),Q=read();
rep(i,1,m) {
int x=read(),y=read(),w=read();
G.add_edge(x,y,w);
} tot=n; dfs1(1,0);
rep(i,n+1,tot) {
for (std:: vector <int>:: iterator j=scc[i].begin();j!=scc[i].end();j++) {
mark[*j]=true;
dis[*j]=0x3f3f3f3f;
}
mark[top[i]]=true;
spfa(top[i]); T.add_edge(top[i],i,0);
// printf("%d %d\n", top[i],i);
for (std:: vector <int>:: iterator j=scc[i].begin();j!=scc[i].end();j++) {
T.add_edge(i,*j,dis[*j]);
// printf("%d %d\n", i,*j);
mark[*j]=false;
}
mark[top[i]]=false;
}
dfs2(dep[1]=1);
for (;Q--;) {
int x=read(),y=read();
int ans=solve(x,y);
printf("%d\n", ans);
}
return 0;
}