1. 程式人生 > >bzoj3047: Freda的傳呼機&bzoj2125: 最短路

bzoj3047: Freda的傳呼機&bzoj2125: 最短路

雙倍經驗題

題意很簡單,求仙人掌兩點間距離

各種情況討論了我一天多...

在膜拜了一種新的建圖方式後終於思路清晰了

思路:首先樹上的很好搞,dis[x]+dis[y]-2*dis[lca(x,y)]

先用SPFA求出1號點到任意點的距離dis[x],這個待會求答案時要用

仙人掌也是一種植物,所以我們要把他變成一棵樹

dfs時把每個簡單環取出,每個環總有一個dfn最小的點,把它記做這個環的根

把所有環上的點向環根連邊,記錄它屬於哪個環bel[x](根不記錄,因為它還有可能是另一個環的節點),順便求出環的長度

環邊去掉,其他邊不變,這就形成了一棵樹


這棵樹有什麼用呢?

首先這棵樹上的點沒有變,只是邊較原仙人掌有所變化

那麼我們就可以求任意兩點x,y,的lca了

接下來就是愉悅的分類討論了

設dep[x]>dep[y]

分別記錄x和y的祖先且是lca的兒子的點fx和fy

1.x和y中一個是lca

畫圖可知這個lca是不是原圖的環都沒有關係

直接return dis[x]-dis[y]

2.fx和fy都在同一個環上

即bel[x]!=0&&bel[x]==bel[y]

那麼ans=dis[x]-dis[fx]+dis[y]-dis[fy]+d,d是fx,和fy在環上的距離

這個畫圖也能知道

d怎麼求,可以在dfs時得到每個點的另一個距離rdis,這個rdis不是到1的最小距離,而是每個環都按一個方向走的距離

或者你可以在取環的時候順便求出環上點到環根的一個方向的距離rdis,這種更好理解一些,雖然我腦子一抽用了上一種方法

這樣就滿足可減了,可以直接用abs(rdis[fx]-rdis[fy])得出fx和fy在環上的一段距離,用len[bel[fx]]-d可得另一種距離,取min即可

3.fx和fy有一個不在環上或x和y不在同一個環上

這個簡單,畫圖即可 ans=dis[x]+dis[y]-dis[lca]*2

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define abs(a) (a>0?a:(-(a)))
const int maxn=50010,maxm=100010,maxk=22;
using namespace std;
int n,m,Q,dis[maxn],head,tail,q[maxm+10],sta[maxn],top,rdis[maxn],rcnt,fa[maxn][maxk],dfn[maxn],last[maxn],bel[maxn],rlen[maxn],dep[maxn];
int pre[maxm],now[maxn],son[maxm],val[maxn],tot,tim;bool bo[maxn],del[maxm],vis[maxn];
void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
void ins(int a,int b,int c){add(a,b,c),add(b,a,c);}
void spfa(){
	memset(dis,63,sizeof(dis));
	head=dis[1]=0,q[tail=1]=1,bo[1]=1;
	while (head<=tail){
		if (++head>maxm) head=1;
		int x=q[head];
		for (int y=now[x];y;y=pre[y]){
			if (dis[son[y]]>dis[x]+val[y]){
				dis[son[y]]=dis[x]+val[y];
				if (!bo[son[y]]){
					if (++tail>maxm) tail=1;
					q[tail]=son[y],bo[son[y]]=1;
				}
			}
		}
		bo[x]=0;
	}
}

void getring(int st,int ed,int id){
	del[id]=del[id^1]=1,rlen[++rcnt]+=val[id];
	for (int x=ed;x!=st;x=son[last[x]^1]){
		bel[x]=rcnt,del[last[x]]=del[last[x]^1]=1;
		ins(st,x,0),rlen[rcnt]+=val[last[x]];
	}
}

void dfs(int x){
	dfn[x]=++tim;
	for (int y=now[x];y;y=pre[y]) if (y!=(last[x]^1)&&(y<=(m*2+1))){
		if (!dfn[son[y]]) last[son[y]]=y,rdis[son[y]]=rdis[x]+val[y],dfs(son[y]);
		else if (dfn[son[y]]<dfn[x]) getring(son[y],x,y);
	}
}

void dfs2(int x){
	vis[x]=1;
	for (int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int y=now[x];y;y=pre[y]) if (!del[y]&&son[y]!=fa[x][0])
		dep[son[y]]=dep[x]+1,fa[son[y]][0]=x,dfs2(son[y]);
}

int query(int x,int y){
	if (dep[x]<dep[y]) swap(x,y);
	//printf("step1: %d %d\n",x,y);
	int a=x,b=y;
	for (int h=dep[x]-dep[y],i=18;h&&i>=0;i--) if (h&(1<<i)) h-=(1<<i),x=fa[x][i];
	//printf("step2: %d %d\n",x,y);
	if (x==y) return dis[a]-dis[b];//puts("cas1:鏈 "),
	for (int i=18;i>=0;i--)
		if (fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	int lca=fa[x][0];
	//if (!x||!y||!lca) return 0;
	if (bel[x]&&bel[x]==bel[y]){
		//puts("cas2:相同的環  ");
		int d=abs(rdis[x]-rdis[y]);d=min(d,rlen[bel[x]]-d);
		return dis[a]+dis[b]-dis[x]-dis[y]+d;
	}
	//puts("cas3:不同的環或不是環  ");
	return dis[a]+dis[b]-2*dis[lca];
}

int main(){
	scanf("%d%d%d",&n,&m,&Q),tot=1;
	for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),ins(x,y,z);
	spfa(),last[1]=-1,dfs(1),dfs2(1);
	for (int i=1,x,y;i<=Q;i++) scanf("%d%d",&x,&y),printf("%d\n",query(x,y));
	return 0;
}

/*
13 18 3
1 2 5

2 14 3
2 9 5
14 9 2

9 15 4
9 10 6
15 10 3

10 11 7
11 12 6
12 13 5
13 10 4

2 3 2
3 4 3
4 5 2
5 6 3
6 7 2
7 8 3
8 3 2

15 12
13 2
15 12
*/


相關推薦

bzoj3047: Freda傳呼機&bzoj2125: 短路

雙倍經驗題 題意很簡單,求仙人掌兩點間距離 各種情況討論了我一天多... 在膜拜了一種新的建圖方式後終於思路清晰了 思路:首先樹上的很好搞,dis[x]+dis[y]-2*dis[lca(x,y)] 先用SPFA求出1號點到任意點的距離dis[x],這個待會求答案時要用

[BZOJ2125]短路(圓方樹DP)

ont int tin ons 最短 bzoj 如果 比較 pri 題意:仙人掌圖最短路。 算法:圓方樹DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圓方樹(與點雙圓方樹的區別在於直接連割邊,也就是存在圓圓邊),然後考慮點u-v的最短路徑,顯然就是:在圓

BZOJ2125: 短路(圓方樹)

%d mes 位置 namespace tdi 分類討論 pac line -s Time Limit: 1 Sec Memory Limit: 259 MBSubmit: 1574 Solved: 651[Submit][Status][Discuss] Descr

【題解】Bzoj2125短路

long str 相對 c++ head code 兩個 turn void   處理仙人掌 ---> 首先建立出圓方樹。則如果詢問的兩點 \(lca\) 為圓點,直接計算即可, 若 \(lca\) 為方點,則需要額外判斷是走環的哪一側(此時與兩個點在環上的相對位置有

bzoj2125 短路——仙人掌兩點間距離

spa bsp ios bzoj2125 處理 dep 答案 pre 最短路 題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2125 仙人掌!模仿 lyd 的代碼寫的,也算是努力理解了; 主要分成 lca 在環上和不

「Nescafé26」 Freda傳呼機短路徑+書上倍增】

試驗 一位 bre 最短路 isp add 交流 實現 continue 題目: 為了隨時與rainbow快速交流,Freda制造了兩部傳呼機。Freda和rainbow所在的地方有N座房屋、M條雙向光纜。每條光纜連接兩座房屋,傳呼機發出的信號只能沿著光纜傳遞,並且傳呼機的

BZOJ2125短路(仙人掌,圓方樹)

return namespace tdi ring fine .com HA names truct 【BZOJ2125】最短路(仙人掌,圓方樹) 題面 BZOJ 求仙人掌上兩點間的最短路 題解 終於要構建圓方樹啦 首先構建出圓方樹,因為是仙人掌,和一般圖可以稍微的不一樣

SPFA 短路

有意 using span 修改 一個 push family memset spfa GeneralLiu 最短路 什麽意思呢 其實就是字面意思嘍 解法多樣 就只介紹 SPFA 了 每次 用一個 "有意義" 的點 更新與之相連點 的 dis

HDU 5294 Tricks Device (大流+短路)

sta names set acm ref () end get 情況 題目鏈接:HDU 5294 Tricks Device 題意:n個點,m條邊。而且一個人從1走到n僅僅會走1到n的最短路徑。問至少破壞幾條邊使原圖的最短路不存在。最多破壞幾條邊使原圖的最短路勁仍存在

【bzoj2324】[ZJOI2011]營救皮卡丘 短路-Floyd+有上下界費用流

之前 %d push 間距 出發 防禦 using mil 之間 原文地址:http://www.cnblogs.com/GXZlegend/p/6832504.html 題目描述 皮卡丘被火箭隊用邪惡的計謀搶走了!這三個壞家夥還給小智留下了赤果果的挑釁!為了皮卡丘,也為

網絡提速(短路

三臺 oid size 註意 減少 組成 getchar() cst etc codevs——1243 網絡提速 時間限制: 1 s 空間限制: 128000 KB 題目等級 : 黃金 Gold

POJ - 1062 昂貴的聘禮(短路Dijkstra)

方案 ref pst 思路 記錄 ron inpu 一個點 != 昂貴的聘禮 Time Limit: 1000MS Memory Limit: 10000KB 64bit IO Format: %I64d & %I64u Subm

vijos 1423 短路or環(有向圖)

取消 main 必須 測試 主辦方 marker ons eof eap 最佳路線 描述 年久失修的賽道令國際汽聯十分不滿。汽聯命令主辦方立即對賽道進行調整,否則將取消其主辦權。主辦方當然必須馬上開始行動。 賽道測評人員經過了三天三夜的數據采集,

洛谷P1027 Car的旅行路線 計算幾何 圖論短路

name ani 但是 ret sqrt bsp include struct == 題意 求某城到某城的最小花費 一個城中有四個機場,一個城中的機場相互可達,用公路到達,但是不同城的公路的單位路程的費不同,兩個不同城的機場(我不知道相同城可不可以)可以通過機場到達,且飛機

【BZOJ2259】[Oibh]新型計算機 短路

進行 mes string ont mda const 文件 queue 個數 【BZOJ2259】[Oibh]新型計算機 Description Tim正在擺弄著他設計的“計算機”,他認為這臺計算機原理很獨特,因此利用它可以解決許多難題。

單源短路徑(短路

ext getchar 路徑 鄰接鏈表 單源最短路 fin struct true com 洛谷——P3371 【模板】單源最短路徑(spfa) 題目描述 如題,給出一個有向圖,請輸出從某一點出發到所有點的最短路徑長度。 輸入輸出格式 輸入格

Currency Exchange(短路

quest ber its 只需要 nging lars script end ive                            poj—— 1860 Currency Exchange Time Limit: 1000

hdu 2544 短路(SPFA算法)

oid rom 表示 max 兩個 amp 取消 get pid 本題鏈接:點擊打開鏈接 本題大意: 首先輸入一個n,m。代表有n個點。m條邊。然後輸入m條邊,每條邊輸入兩個點及邊權。1為起點,n為終點。輸入兩個零表示結束。 解題思路:

【差分約束系統】【短路】【spfa】CDOJ1646 窮且益堅, 不墜青雲之誌。

put pac 時間復雜度 edge 系列 string pri class emp 求一個有n個元素的數列,滿足任意連續p個數的和不小於s, 任意連續q個數的和不大於t。 令sum[i]表示前i項的和(0<=i<=n,sum[0]=0) 那麽題目的條件可轉化為

51nod 1445 變色DNA,短路好題

nbsp 最短 struct pro ble size retext targe 轉換成 1445 變色DNA 題目來源: TopCoder 基準時間限制:1 秒 空間限制:131072 KB 分值: 40 難度:4級算法題 收藏 關註 取消關註 有一只特別