一本通 4 4 例 2 暗的連鎖 題解

2021-09-27 09:24:41 字數 3734 閱讀 8169

題目傳送門

題目大意:給一棵由白邊連線的樹,裡面還有若干條黑邊,問有多少種黑邊和白邊各刪除一條後使圖不連通的方案。

我這可能是全網絕無僅有的沙雕做法了……

正解:倍增 +

++ 樹上差分。

然而我一開始的想法就偏離了正軌……

我的解法:dfs

dfsdf

s 序 +++s

play

splay

splay+

++ 啟發式合併

考慮每一條白邊,假如將它刪掉之後,再刪一條黑邊可以使得這棵樹不連通,當且僅當這條白邊連線的那棵子樹中最多只有一條連向子樹外的黑邊。假如沒有連向子樹外的黑邊,那麼刪除了這條白邊之後,可以再刪除任意一條黑邊達成乙個方案,答案加黑邊數量。假如有一條連向子樹外的黑邊,那麼就只能刪這條黑邊,答案加1

看到子樹,第一時間當然是想到 dfs

dfsdf

s 序,考慮每乙個結點造一棵 spl

ay

splay

spla

y,維護 以他的子樹內的結點為起點 的黑邊的終點的 dfs

dfsdf

s 序。處理完兒子之後,將兒子們的 spl

ay

splay

spla

y 通過啟發式合併與自己的 spl

ay

splay

spla

y 合併。

因為 spl

ay

splay

spla

y 裡面的值是有序的,所以可以利用 dfs

dfsdf

s 序的性質——一棵子樹內的結點的 dfs

dfsdf

s 序是連續的,將自己的 spl

ay

splay

spla

y 內值在自己的子樹內的都刪掉,然後判斷一下自己的 spl

ay

splay

spla

y 的大小,統計答案即可。

ac**(並沒有跑得很快):

#include

#include

#include

using

namespace std;

#define maxn 200010

int n,m;

struct edge

;edge white[maxn*2]

,black[maxn*2]

;int first[maxn]

,fir[maxn]

;void

buildwhiteroad

(int x,

int y)

; first[x]

=len;

}void

buildblackroad

(int x,

int y)

; fir[x]

=len;

}struct node

friend

void

ins(

int,node *&)

;void

check()

voidgo(

int l,

int r,node *

&rt)

//將不在區間[l,r]內的點加入到rt這棵樹內

node *

find

(int c)

//找到值為c的點};

node *root[maxn]

;void

rotate

(node *x)

else

fa->fa=x;x-

>fa=gfa;

if(gfa!=

null

) fa-

>

check()

;x->

check()

;}#define witch(x) (x->fa->zuo==x)

void

splay

(node *x,node *to,node *

&rt)

//splay基操,不多解釋了

if(to==

null

)rt=x;

}void

ins(

int c,node *

&rt)

//往rt這棵樹裡面加乙個值為c的點

node *p=rt-

>

find

(c);

if(c>x)p-

>zuo=

newnode

(c,p)

,splay

(p->zuo,

null

,rt)

;else p-

>you=

newnode

(c,p)

,splay

(p->you,

null

,rt);}

int dfs[maxn]

,last[maxn]

,id=0;

void

dfs_1

(int x,

int fa)

//預處理dfs序以及自己子樹的dfs序範圍

node *

merge

(int l,

int r,node *rt1,node *rt2)

//啟發式合併兩棵splay

intfindrank

(node *now,

int x,

int f1)

//找到x的排名,f1是乙個小的調整,可以結合**理解

node *

findkth

(node *now,

int x)

//找到排名為x的結點

}void

del(node *

&rt,

int l,

int r)

//將rt這棵樹內值在[l,r] 區間內的刪掉

}else

else}}

long

long ans=0;

void

dfs_2

(int x,

int fa)

for(

int i=fir[x]

;i;i=black[i]

.next)

//把以自己為起點的黑邊的終點的dfs序加進來

if(root[x]

!=null

)del

(root[x]

,dfs[x]

,last[x]);

//刪掉沒用的點

if(x!=

1&&root[x]

==null

)ans+=(

long

long

)m;//統計結果

else

if(x!=

1&&root[x]

->size<=

1)ans++;}

intmain()

for(

int i=

1,x,y;i<=m;i++

)dfs_1(1

,0);

dfs_2(1

,0);

printf

("%lld"

,ans)

;}

一本通1593 例 2 牧場的安排

時間限制 1000 ms 記憶體限制 524288 kb 原題來自 usaco 2006 nov.gold farmer john 新買了一塊長方形的牧場,這塊牧場被劃分成 m m 行 n n 列 1 m 12 1 n 12 1 m 12 1 n 12 每一格都是一塊正方形的土地。fj 打算在牧場上...

一本通1664 例 2 取石子遊戲 2

題目描述 有一種有趣的遊戲,玩法如下 玩家 2 人 道具 n 堆石子,每堆石子的數量分別為 x1 x2 xn 規則 遊戲雙方輪流取石子 每人每次選一堆石子,並從中取走若干顆石子 至少取 1 顆 所有石子被取完,則遊戲結束 如果輪到某人取時已沒有石子可取,那此人算負。假如兩個遊戲玩家都非常聰明,問誰勝...

一本通 1 1 例 2 種樹

題目傳送門 這題的題目問的是要滿足所有居民的建議,至少要種多少棵樹。對於這種題目,我們首先想到的應該是貪心策略。貪心策略 首先按右端點從小到大排序,因為要求樹最少,所以要盡量放在右端點。然後定義乙個bool陣列判斷該點是否種過樹即可。從右端點開始種,可以讓更多的樹照顧到更右側的端點,這樣就能使種的數...