樹鏈剖分,線段樹 洛谷 5127 子異和

2021-09-29 00:01:16 字數 3705 閱讀 9248

多組詢問,每次把樹上的一條簡單路徑中的點權扔入集合中,求該集合的子異和,子異和定義為所有非空子集的異或和的和,而且需要支援區間異或

考慮某一位滿足異或和為1的子集數,若設異或某一位為k

kk為1的數量為h

kh_k

hk​,那麼結果應為cnt

k=2n

−hk×

∑i=1

⌊hk2

⌋c(n

,2i−

1)=2

n−

1cnt_k=2^\times \sum_^\rfloor}c(n,2i-1)=2^

cntk​=

2n−h

k​×i

=1∑⌊

2hk​

​⌋​c

(n,2

i−1)

=2n−

1,竟然只與hkhk

hk是否為0有關,最終答案竟然變成了2n−

1×or

su

m2^\times orsum

2n−1×o

rsum

,但是如何實現區間異或,顯然只有或是不夠的,所以我們可能要引入與,分類討論,其實也很好理解的呀

t an

d=(t

and&

!z)∣

(!to

r&z)

,tor

=(!t

and&

z)(t

or&!

z)

t_=(t_\& !z)|(!t_\& z),t_=(!t_\&z)(t_\& !z)

tand​=

(tan

d​&!

z)∣(

!tor

​&z)

,tor

​=(!

tand

​&z)

(tor

​&!z

)所以就樹剖套線段樹解決

#include

#include

#define rr register

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<13,stdin)),p1==p2?eof:*p1++)

using

namespace std;

typedef

unsigned uit;

const uit n=

200101

,mod=

1000000007

;struct nodee[n<<1]

;char buf[

1<<13]

,*p1,

*p2;

uit wnd[n<<2]

,wor[n<<2]

,p[n]

,lazy[n<<2]

,ls[n]

,n,tot,k=

1,a[n]

,a[n]

,top[n]

,dep[n]

,fat[n]

,dfn[n]

,son[n]

,big[n]

;inline uit iut()

inline

void

print

(uit ans)

inline uit mo

(uit x,uit y)

inline

void

change

(uit k,uit z)

inline

void

pdown

(uit k)

inline

void

build

(uit k,uit l,uit r)

rr uit mid=

(l+r)

>>1;

build

(k<<

1,l,mid)

;build

(k<<1|

1,mid+

1,r)

; wnd[k]

=wnd[k<<1]

&wnd[k<<1|

1],wor[k]

=wor[k<<1]

|wor[k<<1|

1];}

inline uit query

(uit k,uit l,uit r,uit x,uit y)

inline

void

update

(uit k,uit l,uit r,uit x,uit y,uit z)

pdown

(k); rr uit mid=

(l+r)

>>1;

if(y<=mid)

update

(k<<

1,l,mid,x,y,z)

;else

if(x>mid)

update

(k<<1|

1,mid+

1,r,x,y,z)

;else

update

(k<<

1,l,mid,x,mid,z)

,update

(k<<1|

1,mid+

1,r,mid+

1,y,z)

; wnd[k]

=wnd[k<<1]

&wnd[k<<1|

1],wor[k]

=wor[k<<1]

|wor[k<<1|

1];}

inline

void

update

(uit x,uit y,uit z)

if(dep[x]

>dep[y]

) x^

=y,y^

=x,x^

=y;update(1

,1,n,dfn[x]

,dfn[y]

,z);

}inline uit query

(uit x,uit y)

if(dep[x]

>dep[y]

) x^

=y,y^

=x,x^

=y; cnt+

=dfn[y]

-dfn[x]+1

,ans|

=query(1

,1,n,dfn[x]

,dfn[y]);

return

1ll*ans*p[cnt-1]

%mod;

}inline

void

dfs1

(uit x,uit fa)

}inline

void

dfs2

(uit x,uit linp)

signed

main()

,ls[x]

=k; e[

++k]

=(node)

,ls[y]

=k;}

for(rr uit i=

1;i<=n;

++i) a[i]

=iut()

,p[i]=mo

(p[i-1]

,p[i-1]

);dfs1(1

,0),

dfs2(1

,1),

build(1

,1,n);

while

(m--

)return0;

}

P5127 子異和 線段樹,樹鏈剖分,位運算

定義乙個序列的子異和為所有自己的異或和的和。然後有點權的樹,要求支援路徑異或和路徑求子異和。首先樹鏈剖分是肯定的,然後我們考慮用哪個資料結構。從每個位單獨分析,乙個長度為n nn的集合,然後cnt xcnt x cntx 表示有多少數的二進位制第x xx位為0 00然後對於乙個位可以貢獻的答案是2c...

LCA 樹鏈剖分 線段樹

給出乙個 n 個節點的有根樹 編號為 0 到 n 1 根節點為 0 乙個點的深度定義為這個節點到根的距離 1 設 dep i 表示點 i 的深度,lca i,j 表示 i 與 j 的最近公共祖先。有 q 次詢問,每次詢問給出 l,r,z 求 dep lca i,z 即,求在 l,r 區間內的每個節點...

poj 3237 樹鏈剖分 線段樹

題意 給一棵樹,三種操作。將第i條邊的權值改為v,將a到b的路徑上的邊的權值全部取反,求a到b路徑上邊的權值的最大值。思路 明顯的樹鏈剖分,加上線段樹的操作。因為有取反的操作所以每個區間要記錄最大值和最小值。查詢兩點間的路徑時,用求公共祖先的方式去求。include include includec...