給出一棵邊帶權的節點數量為n的樹,初始樹上所有節點都是白色。有兩種操作:
c x,改變節點x的顏色,即白變黑,黑變白
a,詢問樹中最遠的兩個白色節點的距離,這兩個白色節點可以重合(此時距離為0)。
n (n <= 100000) q <= 200000
時限1s
如果沒有修改的話,直接點分治,記錄子樹最深的白點即可。
但是有修改。
發現,點分治的遞迴層數是o(logn)的
而且這個遞迴的聯通塊的根形成乙個樹形結構。不妨叫點分樹。
我們的答案是在所有遞迴出來的塊裡ans取max
發現,每次改變乙個點的顏色,會影響自己的聯通塊,以及點分樹上這個點的所有father的答案。
樹高logn
所以,我們考慮暴力修改每一層的答案。
用三個堆來維護。
乙個堆h0,維護這個點p所代表的點分樹的聯通塊中所有點到點分樹上p的father的距離(樹上實際距離)。
(好處是,修改的時候,直接自底向上,父親只要乙個,這樣不需要在上層再考慮哪個子樹變了)
另乙個堆h1,維護這個點p的所有兒子的堆頂的值。
我們從乙個點p的h1堆裡面,找到最大的和次大的,做和就是這一層的最大答案。
如果p是白點,那麼答案可以只要最大的。而且ans最少是0
第三個堆,維護所有點代表的聯通塊的ans。最終答案就在這裡。
然後,所有的修改,都是刪除之後再插入。
堆的刪除,用懶惰堆即可。
**:(實現細節較多:例如堆的empty判斷)
(堆中不用記錄答案出自**,隨便刪除乙個,剩下那個就是沒有刪除的。是沒有區別的。直接int的堆即可)
//luogu-judger-enable-o2
#include#define reg register int
#define il inline
#define numb (ch^'0')
using
namespace
std;
typedef
long
long
ll;il
void rd(int &x)
il void prin(int
x)namespace
miraclee[
2*n];
inthd[n],cnt;
il void add(int x,int y,int
z)int
fa[n];
intsz[n];
intc[n];
priority_queue
h[2][n],d[2
][n],hh,dd;
int dis[n][20
];int
dep[n];
intnowsz;
intrt,mxsz[n];
intans[n];
bool
vis[n];
intgen;
il void dfs1(int x,int ff,int
d) mxsz[x]=max(mxsz[x],nowsz-sz[x]);
if(mxsz[x]<=nowsz/2)}
il void dfs2(int x,int ff,intd)}
il void clear(int x,intk)}
il void upda(int
x) clear(x,1);
if(!h[1
][x].empty())
h[1][x].push(tmp);
}}il
int divi(int x,int d,int
ff) }
upda(now);
//cout<<" rt "return
now;
}il
void wrk(int
x)
x=fa[x];
--nd;}}
else
x=fa[x];
--nd;}}
}int
main()
nowsz=n;
gen=divi(1,1,0
);
intm;
rd(m);
char ch[10
];
while(m--)
if(!hh.size())
else}}
else
//cout<<" ans------- "for(reg i=1;i<=n;++i)
}
return0;
}}intmain()
/*author: *miracle*
date: 2018/11/28 9:20:15
*/
你也可以順帶ac[zjoi2007]捉迷藏
QTREE4小結 我寫的是樹剖
為啥說是小結。這辣雞題我寫了兩天。順帶其中參觀了一下scoi的大新聞 這題思路首先是樹剖,剖出來之後,考慮對於每個點維護乙個d1,d2,表示從這個點往下走,不經過自己所在重鏈的邊,到達乙個黑點的最長路徑和次長路徑。如果下面黑點不足就是 inf了。處理出來之後,對於一條鏈,線段樹維護這麼幾個值,lv ...
點分治 動態點分治
實在拖得太久了。先扔掉資料 分治的核心是盡量把乙個整體分成接近的兩個部分,這樣遞迴處理可以讓複雜度從n 變成nlogn。兩個問題,如何區分和如何算答案。對於第乙個問題,重心,然後就是找重心的方法,兩個dfs,對於第二個問題,對於每個重心算當前塊中每個點到重心的答案,然後由重心分開的塊要把多餘的資訊去...
點分治與動態點分治
點分治一般是用於解決樹上路徑問題。樹的重心 把重心這個點割掉後,使所形成的最大的聯通塊大小最小的點。可以證明重心子樹的大小最大不會超過 n over 2 重心可以通過 dfs 一遍求出。maxsiz x 表示割掉點x後所形成的的最大的聯通塊的大小 void dfs int x,int fa max ...