Bzoj 3694 最短路 樹鏈剖分

2022-03-30 13:24:09 字數 3248 閱讀 7847

time limit: 5 sec  memory limit: 256 mb

submit: 67  solved: 34

[submit][status][discuss]

給出乙個n個點m條邊的無向圖,n個點的編號從1~n,定義源點為1。定義最短路樹如下:從源點1經過邊集t到任意一點i有且僅有一條路徑,且這條路徑是整個圖1到i的最短路徑,邊集t構成最短路樹。 給出最短路樹,求對於除了源點1外的每個點i,求最短路,要求不經過給出的最短路樹上的1到i的路徑的最後一條邊。

第一行包含兩個數n和m,表示圖中有n個點和m條邊。

接下來m行,每行有四個數ai,bi,li,ti,表示圖中第i條邊連線ai和bi權值為li,ti為1表示這條邊是最短路樹上的邊,ti為0表示不是最短路樹上的邊。

輸出n-1個數,第i個數表示從1到i+1的要求的最短路。無法到達輸出-1。

5 93 1 3 1

1 4 2 1

2 1 6 0

2 3 4 0

5 2 3 0

3 2 2 1

5 3 1 1

3 5 2 0

4 5 4 0

6 7 8 5

對於100%的資料,n≤4000,m≤100000,1≤li≤100000

題解:首先,先處理出最短路樹中每個點i距源點1的最短距離dis[i]。

因為要求不經過最短路樹的最後一條邊,所以要到乙個點,必須要從和這個點在同乙個環中的另外一邊繞過去。

例如:設我們要到u點,我們還有不在最短路樹上的兩個點x,y。t為lca(x,y)。假如u點在y到t的路徑上,我們既然不能從1經過t到u,那我們只有從1 -> t -> x -> y ->u。這樣我們可以用dis[x]+val[x][y]+dis[y]-dis[u]來更新ans。因為dis[u]是不變的,所以我們可以最後去減去dis[u]。之前只用維護dis[x]+val[x][y]+dis[y]即可。

1 #include2

using

namespace

std;

3#define maxn 4010

4#define maxm 100010

5#define inf 1e9

6struct

node

7edge[maxn*2

];10

struct

node

11tree[maxn*5

];14

int cnt,head[maxn],n,size[maxn],deep[maxn],p[maxn][12

],dis[maxn],pos[maxn],belong[maxn],s1[maxm],s2[maxm],s3[maxm],size;

15bool

vis[maxn];

16void addedge(int bb,int ee,int

vv)17

20void addedge1(int bb,int ee,int

vv)21

24int

read()

2528

while(ch>='

0'&&ch<='9')

29return s*fh;30}

31void dfs1(int

u)3246}

47}48void

ycl()

4957}58

}59void dfs2(int u,int

chain)

6068

if(k==0)return;69

dfs2(k,chain);

70for(i=head[u];i!=-1;i=edge[i].next)

7175}76

int lca(int x,int

y)7790}

91return p[x][0

];92}93

void build(int k,int l,int

r)94

97int mid=(l+r)/2

;98 build(k*2

,l,mid);

99 build(k*2+1,mid+1

,r);

100}

101void pushup(int

k)102

106void pushdown(int

k)107

117}

118void change(int k,int l,int r,int

c)119

121pushdown(k);

122int mid=(tree[k].left+tree[k].right)/2

;123

if(r<=mid)change(k*2

,l,r,c);

124else

if(l>mid)change(k*2+1

,l,r,c);

125else

126pushup(k);

127}

128void solve_change(int x,int f,int

c)129

135if(x!=f)change(1,pos[f]+1

,pos[x],c);

136}

137int query(int k,int l,int

r)138

146int solve_query(int x,int

f)147

154if(x!=f)mn=min(mn,query(1,pos[f]+1

,pos[x]));

155return

mn;156

}157

int ask(int k,int

lr)158

165int

main()

166178

else

addedge1(a,b,l);

179}

180 memset(p,-1,sizeof(p));size=0

;181 dfs1(1

);ycl();

182 dfs2(1,1

);183 build(1,1

,n);

184//

for(i=1;i<=n;i++)change(1,pos[i],pos[i],dis[i]);

185for(i=1;i<=tot;i++)

186192

for(i=2;i<=n;i++)

193200

return0;

201 }

bzoj3694 最短路 樹鏈剖分

給出乙個n個點m條邊的無向圖,n個點的編號從1 n,定義源點為1。定義最短路樹如下 從源點1經過邊集t到任意一點i有且僅有一條路徑,且這條路徑是整個圖1到i的最短路徑,邊集t構成最短路樹。給出最短路樹,求對於除了源點1外的每個點i,求最短路,要求不經過給出的最短路樹上的1到i的路徑的最後一條邊。第一...

BZOJ 3694 最短路 樹鏈剖分 倍增

下個月就是noip10連測試,還有什麼大學先修課考試,這段時間一直很忙但是還是抽出時間來複習一下版子,前段時間一直在搞spfa的各種建模,這段時間就來複習一下資料結構吧。首先就來不太好打的樹鏈剖分。嗯,開心,就每天寫一點點居然叫了兩遍就ac了,剛準備自己出資料還沒出,就抱著嘗試的想法提交了,居然ac...

bzoj3694 最短路 樹鏈剖分 線段樹

最短路 bzoj 3694 題目大意 給你乙個n個點m條邊的無向圖,源點為1,並且以點1為根給出最短路樹。求對於2到n的每個點i,求最短路,要求不經過給出的最短路樹上的1到i的路徑上的最後一條邊。注釋 1 le n le 4000 1 le m le 10 5 想法 對於任意兩個點u和v,滿足u和v...