BZOJ 3653 談笑風生

2021-08-21 16:18:40 字數 1338 閱讀 4919

題目在這裡呀!

個人認為是一道很好的題目,原來可持久化線段樹還能這麼用,看題解之前還是沒有想到啦要批評!那就寫個題解補償一下?

給你一棵有根樹,n個節點,有q次詢問,每次詢問,給出兩個數x(1<=x<=n),d,求有多少有序元組(y,z)滿足 x,y,z互不相同,x,y均為z的祖先,且x,y之間的距離超過d。

y的位置有兩種情況

1、y是x的祖先

那麼y一定是在x到根節點的路徑上,有min(dep[x],d)種取法,然後z有size[x]種取法,故方案數為size[x]*min(dep[x],d)。

2、y是x的孩子

那麼方案數為∑i

size

[i] ∑is

ize[

i]

(dep[i]-dep[x]<=d)

怎麼求這個?考慮按dfs序來建可持久化線段樹,然後深度來作為節點編號,節點裡放size。吼吼吼為什麼一開始沒有想到沒有想到?!

然後就迎刃而解啦(還傻傻地忘記寫了乙個return被嘲笑qwq)

//suplex

#include

#include

#include

#include

#include

#define ll long long

#define n 400400

using

namespace

std;

int n,q,u,v,cnt,tot,vet[n+n],next[n+n],head[n],l[n],r[n],opp[n],dep[n],size[n],p,k,maxd;

int root[n];

struct segment_treet[8000000];

void add_edge(int u,int v)

void dfs(int u,int fa)

r[u]=tot;

}inline

void modify(int &rt,int p,int l,int r,int x,int delta)

inline ll query(int rt,int l,int r,int x,int y)

int main()

dfs(1,-1);

for(int i=1;i<=n;i++) maxd=max(maxd,dep[i]);

cnt=0;

for(int i=1;i<=n;i++) modify(root[i],root[i-1],0,maxd,dep[opp[i]],size[opp[i]]);

while(q--)

return

0;}

BZOJ3653 談笑風生

對於每乙個詢問我們可以提出 ans min dep u 1,k size u 1 u子樹中到u距離 k的節點的子樹節點和 顯然後面那個東西是可以用可持久化線段樹搞得 好了 include include include include using namespace std char c defin...

BZOJ3653 談笑風生

題目大意 給一棵樹,每次詢問給定a,k,求三元組 a,b,c 的數量滿足 1.a和b都是c的祖先 2.a和b在樹上距離不超過k 3.a,b,c互不相同 顯然abc肯定形成豎著的一條鏈 分兩種情況討論 1.b在a的上方,也就是說對於任意合法的b,c可以在a的子樹裡隨便選,這個方案數是可以直接算出來的 ...

BZOJ3653 談笑風生

設d x 表示x到根的距離 size x 表示x的子樹大小 不含自己 求出dfs序後按dfs序建主席樹,線段樹中區間 a,b 表示深度在 a,b 範圍內的size的和 查詢x,y的答案 size x min d x y dfs序在st x 1到en x 之間且深度在d x 1到d x k之間的siz...