ZJOI 2007 Hide 捉迷藏 題解

2021-09-25 01:20:21 字數 3993 閱讀 6115

題目傳送門

題目大意:有乙個 n

nn 個點的樹,每個節點有黑白兩種顏色之一,一開始全是白點,現在有兩種操作。操作一:修改某個點的顏色;操作二,詢問最遠的兩個白點的距離。

因為跟樹上的點對距離有關係,很自然的就想到樹上點分治,但是有修改操作,於是使用動態點分治即可。

那我們考慮對於每乙個重心如何更新答案。

對於每乙個重心,它能產生的貢獻,就是子樹中離自己最遠的兩個白點的距離之和,並且要求這兩個白點來自該重心的兩個不同的子樹中。

那麼因為有修改操作,於是我們需要用乙個堆來維護這個重心的每一棵子樹提供的那個最遠的白點,然後取這個堆中的最大值和次大值相加便可以更新答案。

那麼顯然,我們還需要乙個堆,去維護每一棵子樹中每乙個白點到重心的距離。

最後還需要乙個堆,將每乙個重心求出的答案進行維護,最後取堆頂便是答案。

**嘛……自己都覺得醜,不願意看的還是別看了,,

我盡量把注釋寫明白點= =

#include

#include

#include

#include

#include

using

namespace std;

#define maxn 100010

int n,m;

struct node

;node e[

2*maxn]

;int first[maxn]

;inline

void

buildroad

(int x,

int y)

; first[x]

=len;

}vector< map<

int,

int>

> pos[maxn]

;//pos[i][j][k]表示k在dui1[i][j]中的位置

int bianhao[maxn]

,tt=0;

//bianhao[i]表示i在duians中的位置

map<

int,

int> position[maxn]

;//position[i][j]表示j在dui2[i]中的位置

//堆 vector a;

int l;()

);l=0;

}voidup(

int x)

}voidup(

int x,

int y)

}voidup(

int x,

int tr,

int num)

}void

add(

int x,

int y));

l++; bianhao[y]

=l;up

(l);

}void

add(

int x,

int y,

int num));

l++; position[num]

[y]=l;

up(l,num);}

void

add(

int x,

int y,

int tr,

int num));

//這裡的第三個引數下面有用

l++; pos[tr]

[num]

[y]=l;

up(l,tr,num);}

void

down

(int x)

}void

down

(int x,

int num)

}void

down

(int x,

int tr,

int num)

}}dui2[maxn]

,duians;

;//dui1[i][j]是乙個堆,用來維護 以i的第j個兒子 為根的子樹內每個點到 i的第j個兒子的距離

//dui2[i]也是乙個堆,用來維護i的子樹們提供的最遠白點,也就是用dui1[i][j]的堆頂來造乙個堆

//duians還是乙個堆,用來維護每乙個重心提供的答案,duians的堆頂就是答案

bool v[maxn]

;//v[i]表示i這個點是否被分治過,建完樹之後用來標記這個點的顏色,true為白色,false為黑色

int son[maxn]

,mson[maxn]

,root,size;

int tot[maxn]

;//表示x這個重心的兒子數

map<

int,

int> s[maxn]

;//s[x][y]表示y是x的第幾個兒子

void

getroot

(int x,

int fa)

//尋找重心

if(size-son[x]

>mson[x]

)mson[x]

=size-son[x];if

(mson[x]

)root=x;

}int dis[maxn]

;void

getdis_bt

(int x,

int fa,

int tr,

int num)

//得到每個點的距離,構建dui1

}int fa[maxn]

,con[maxn]

;inline

intwork

(int x,

int y,

int z)

map<

int,

int>won;

void

buildtree

(int x,

int ssize)

if(dui2[x]

.l==

0)duians.

add(

0,x)

;else

if(dui2[x]

.l==

1)duians.

add(dui2[x]

.a[1

].y,x)

;else

if(dui2[x]

.l==

2)duians.

add(dui2[x]

.a[1

].y+dui2[x]

.a[2

].y,x)

;else

if(dui2[x]

.l>

2)duians.

add(

work

(dui2[x]

.a[1

].y,dui2[x]

.a[2

].y,dui2[x]

.a[3

].y)

,x);

}int total;

voidgo(

int x,

int y,

int point)

void

read

(int

&x)int

main()

root=

0;mson[root]

=999999999

;for

(int i=

1;i<=n;i++

) dui1[i]

.push_back

(wan)

,pos[i]

.push_back

(won)

;//填充vector的0位置

size=n;

getroot(1

,0);

buildtree

(root,n)

;read

(m);

for(

int i=

1;i<=m;i++)if

(fa[x]!=0

)go(fa[x]

,con[x]

,x);}}

}

ZJOI2007 棋盤製作

題目描述 西洋棋是世界上最古老的博弈遊戲之一,和中國的圍棋 象棋以及日本的將棋同享盛名。據說西洋棋起源於易經的思想,棋盤是乙個8 8大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。而我們的主人公小q,正是西洋棋的狂熱愛好者。作為乙個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好朋友小w...

zjoi2007棋盤分割

西洋棋是世界上最古老的博弈遊戲之一,和中國的圍棋 象棋以及日本的將棋同享盛名。據說西洋棋起源於易經的思想,棋盤是乙個8 8大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。而我們的主人公小q,正是西洋棋的狂熱愛好者。作為乙個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好朋友小w決定將棋盤...

ZJOI2007 報表統計

不想描述了,心累。兩個操作分別用splay和線段樹來維護 全域性的差值最小直接用splay在插入的時候維護前驅後繼即可 相鄰最小差值我們可以這樣搞 首先 用線段樹維護相鄰的最小值 可以注意到插入元素的操作,如果是在乙個元素之後反覆插入,這些元素之間更新出來的最小值是不會發生改變的。只有元素與元素之間...