洛谷P3899 湖南集訓 談笑風生(線段樹合併)

2022-08-21 04:48:16 字數 1529 閱讀 6940

為了學長鏈剖分開的題,結果還是忍不住寫了個線段樹合併

首先不難發現:$b$ 要麼是 $a$ 的祖先,要麼是 $a$ 的後代。

$b$ 是 $a$ 的祖先很好弄,因為 $c$ 的數量始終等於 $size_a-1$;對於 $b$ 要麼是 $a$ 的後代的情況,那麼就是求 $a$ 的子樹中和它深度差不超過 $k$ 的點的 $size-1$ 之和,按照深度插進線段樹以後合併一下即可。

#include#include

#define for(i,a,b) for(i=(a);i<=(b);++i)

using

namespace

std;

typedef

long

long

ll;const

int n=300050

;const

int buf=1

<<21

;char rb[buf],*rs,*rt,wb[buf+50

];int wp=-1

;inline

char gc()

inline

void flush()

inline

intrd()

short buf[25

];inline

void

wt(ll x)

wb[++wp]=x|48

;

while(l>=0)wb[++wp]=buf[l--]|48

; wb[++wp]='\n'

;}int g[n],to[n<<1],nxt[n<<1],sz,dep[n],siz[n],rt[n],lc[n*20],rc[n*20

],tot,n;

ll sum[n*20

],s[n];

vector

k[n],id[n];

inline

int min(int a,int b)

inline

void adde(int u,int

v)void add(int &o,int l,int r,int x,intk)}

int merg(int u,int

v)ll query(

int o,int l,int r,int x,int

y)void dfs(int u,int

fa) for(i,

0,(int)k[u].size()-1)s[id[u][i]]=query(rt[u],1,n,dep[u]+1,min(n,dep[u]+k[u][i]))+(ll)min(dep[u]-1,k[u][i])*(siz[u]-1

); add(rt[u],

1,n,dep[u],siz[u]-1);}

intmain()

for(i,

1,q)

dfs(

1,0);

for(i,

1,q)wt(s[i]);

flush();

return0;

}

view code

洛谷 P3899 湖南集訓 談笑風生

原題鏈結 題目大意 有一棵 n nn 個節點的有根樹,有 m mm 組詢問 每次詢問給出 a,k a,ka,k,求有多少個三元組 a,b,c a,b,c a,b,c 滿足 a,b a,ba,b 都是 c cc 的祖先,並且 a,b a,ba,b 之間的距離不超過 kkk 剛開始沒有思路,看了題解的分...

洛谷P3899 湖南集訓 談笑風生

設t 為一棵有根樹,我們做如下的定義 設a和b為t 中的兩個不同節點。如果a是b的祖先,那麼稱 a比b不知道 高明到 去了 設a 和 b 為 t 中的兩個不同節點。如果 a 與 b 在樹上的距離不超過某個給定 常數x,那麼稱 a 與b 談笑風生 給定一棵n個節點的有根樹t,節點的編號為1 到 n,根...

P3899 湖南集訓 談笑風生

傳送門 首先 a,b,c 肯定在一條鏈上。當 b 為 a 的祖先時,a 的子樹中所有與它不同的點都可以作為點 c 當 a 為 b 的祖先時,b 的子樹中所有與它不同的點都可以作為答案 我會說我以前根本沒寫過線段樹合併結果完全不知道錯在 麼 luogu judger enable o2 minamot...