圆方树练习。
首先搞出圆方树(建树)。注意在建树的过程中即Tarjan时要同时记录三个信息:1.环的大小。 2.环上每个点到环顶点的距离。 3.最优距离在那一边。
这些都很容易求出来。然后我们把圆点到方点的边权赋为环到顶点的最短距离,方点到圆点的赋为0。
对于每次询问的两个点,询问在圆方树上的LCA,如果LCA是圆点,直接计算即可。下面分析方点的情况。
如果两点的LCA是方点,那么显然在原仙人掌的环上。
这时候对于这个可以选择两条路径,根据题目显然不能暴力走。
对于仙人掌上的两个点,因为我们已经求出最优距离应该走哪一边,而且我们知道了环的大小,所以相对来时没那么优的一条路径也可以计算出来。
所以如果两个点的最优选择是不同方向的,直接用环的大小减去即可。如果是相同方向的,分别计算,取MIN即可。
//BZOJ2125 //by Cydiater //2017.2.13 #include <iostream> #include <queue> #include <map> #include <cstring> #include <string> #include <cstdlib> #include <cstdio> #include <iomanip> #include <algorithm> #include <ctime> #include <cmath> #include <bitset> #include <set> #include <vector> #include <complex> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) #define cmax(a,b) a=max(a,b) #define cmin(a,b) a=min(a,b) #define Auto(i,node) for(int i=LINK[node];i;i=e[i].next) const int MAXN=1e5+5; const int oo=0x3f3f3f3f; inline int read(){ char ch=getchar();int x=0,f=1; while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int N,M,Q,NN,Girth[MAXN]; vector<int>E[MAXN],W[MAXN]; bool cho[MAXN]; struct Info{ int sx,sy,lca; }; struct Graph{ int LINK[MAXN],len,dfn[MAXN],low[MAXN],stack[MAXN],top,dfs_clock,dep[MAXN],fa[MAXN][25],dis[MAXN][25]; struct edge{ int y,next,v; }e[MAXN]; inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;} inline void Insert(int x,int y,int v){insert(x,y,v);insert(y,x,v);} int Col(int id){ int dist=0,siz=E[id].size(); up(i,0,siz-1){ int x=E[id][i],y=E[id][(i+1)%siz]; Auto(j,x)if(e[j].y==y){ dist+=e[j].v; W[id].push_back(e[j].v); } } return dist; } void Tarjan(int node){ dfn[node]=low[node]=++dfs_clock; stack[++top]=node; Auto(i,node)if(!dfn[e[i].y]){ Tarjan(e[i].y); cmin(low[node],low[e[i].y]); if(low[e[i].y]>=dfn[node]){ NN++;int tmp; do{ tmp=stack[top--]; E[NN].push_back(tmp); }while(tmp!=e[i].y); E[NN].push_back(node); Girth[NN]=Col(NN); } }else cmin(low[node],dfn[e[i].y]); } void DFS(int node,int father,int deep){ fa[node][0]=father;dep[node]=deep; Auto(i,node)if(e[i].y!=father) DFS(e[i].y,node,deep+1); if(node>N){ dis[node][0]=0; int siz=E[node].size(),dist=0; down(j,siz-2,0){ dist+=W[node][j]; dis[E[node][j]][0]=min(dist,Girth[node]-dist); if(dis[E[node][j]][0]==dist) cho[E[node][j]]=0; else cho[E[node][j]]=1; } } } void Get_Ancestor(){ up(i,1,20)up(node,1,N)if(fa[node][i-1]){ fa[node][i]=fa[fa[node][i-1]][i-1]; dis[node][i]=dis[node][i-1]+dis[fa[node][i-1]][i-1]; } } Info LCA(int x,int y){ if(x==y) return (Info){0,0,x}; if(dep[x]<dep[y])swap(x,y); down(i,20,0)if(dep[x]-(1<<i)>=dep[y])x=fa[x][i]; if(x==y) return (Info){0,0,x}; down(i,20,0)if(fa[x][i]!=0&&fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; } return (Info){x,y,fa[x][0]}; } int Get(int node,int aim){ int ans=0; down(i,20,0)if(dep[node]-(1<<i)>=dep[aim]){ ans+=dis[node][i]; node=fa[node][i]; } return ans; } }G1,G2; namespace solution{ void Prepare(){ N=read();M=read();Q=read(); while(M--){ int x=read(),y=read(),v=read(); G1.Insert(x,y,v); } NN=N; G1.Tarjan(1); up(i,N+1,NN){ int siz=E[i].size(); up(j,0,siz-1)G2.Insert(i,E[i][j],0); } G2.DFS(1,0,0); G2.Get_Ancestor(); //up(i,1,N)cout<<G2.dis[i][0]<<endl; } void Solve(){ while(Q--){ int x=read(),y=read(),ans=0; Info info=G2.LCA(x,y); int lca=info.lca,sx=info.sx,sy=info.sy; if(lca>N){ int tmp; if(cho[sx]^cho[sy]) tmp=G2.dis[sx][0]+G2.dis[sy][0]; else tmp=min(Girth[lca]-G2.dis[sx][0]+G2.dis[sy][0],Girth[lca]-G2.dis[sy][0]+G2.dis[sx][0]); ans=G2.Get(x,sx)+G2.Get(y,sy)+min(G2.dis[sx][0]+G2.dis[sy][0],Girth[lca]-tmp); } else ans=G2.Get(x,lca)+G2.Get(y,lca); printf("%d\n",ans); } } } int main(){ using namespace solution; Prepare(); Solve(); return 0; }
时间: 2024-10-20 06:59:37