題目傳送門
題目大意:有乙個 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在插入的時候維護前驅後繼即可 相鄰最小差值我們可以這樣搞 首先 用線段樹維護相鄰的最小值 可以注意到插入元素的操作,如果是在乙個元素之後反覆插入,這些元素之間更新出來的最小值是不會發生改變的。只有元素與元素之間...