為了學長鏈剖分開的題,結果還是忍不住寫了個線段樹合併
首先不難發現:$b$ 要麼是 $a$ 的祖先,要麼是 $a$ 的後代。
$b$ 是 $a$ 的祖先很好弄,因為 $c$ 的數量始終等於 $size_a-1$;對於 $b$ 要麼是 $a$ 的後代的情況,那麼就是求 $a$ 的子樹中和它深度差不超過 $k$ 的點的 $size-1$ 之和,按照深度插進線段樹以後合併一下即可。
#include#includeview code#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;
}
洛谷 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...