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

2021-09-24 01:44:12 字數 3840 閱讀 3107

定義乙個序列的子異和為所有自己的異或和的和。

然後有點權的樹,要求支援路徑異或和路徑求子異和。

首先樹鏈剖分是肯定的,然後我們考慮用哪個資料結構。

從每個位單獨分析,乙個長度為n

nn的集合,然後cnt

xcnt_x

cntx

​表示有多少數的二進位制第x

xx位為0

00然後對於乙個位可以貢獻的答案是2cn

tx−1

∗2n−

cntx

=2n−

12^*2^=2^

2cntx​

−1∗2

n−cn

tx​=

2n−1

,但是若cnt

x==0

cnt_x==0

cntx​=

=0時答案是0。

也就是每個位如果cnt

x≠

0cnt_x\neq 0

cntx​̸

​=0那麼就可以貢獻2x∗

2n−1

2^x*2^

2x∗2n−

1的答案。

其實我們發現區間或值為sum

(or)

sum(or)

sum(or

)那麼答案就是2n−

1∗su

m(or

)2^*sum(or)

2n−1∗s

um(o

r)。然後我們區間查詢就可以用線段樹搞了,我們考慮如何區間查詢

我們依舊是每個位進行分析,若第x

xx位為0那麼保持不變,如果為1那麼久等於∼su

m(an

d)

\sim sum(and)

∼sum(a

nd)

所以我們可以得出

s um

(or)

′=(s

um(o

r)&∼

a)∣(

∼sum

(and

)&a)

sum(or)'=(sum(or)\& \sim a)|(\sim sum(and)\&a)

sum(or

)′=(

sum(

or)&

∼a)∣

(∼su

m(an

d)&a

)然後我們多維護乙個sum

(and

)sum(and)

sum(an

d)s um

(and

)′=(

sum(

and)

&∼a)

∣(∼s

um(o

r)&a

)sum(and)'=(sum(and)\& \sim a)|(\sim sum(or)\&a)

sum(an

d)′=

(sum

(and

)&∼a

)∣(∼

sum(

or)&

a)圓滿解決該題

#include

#include

#define ll long long

using

namespace std;

const ll n=

201000

,xjq=

1e9+7;

struct tree_node

;struct edge_nodea[n*2]

;ll tot,ls[n]

,n,m,w[n]

,cnt,pow[n]

;ll id[n]

,siz[n]

,seg[n]

,son[n]

,top[n]

,dep[n]

,f[n]

;struct line_cut_tree

ll mid=

(l+r)/2

;build

(x*2

,l,mid)

;build

(x*2+1

,mid+

1,r)

; t[x]

.sor=t[x*2]

.sor|t[x*2+

1].sor;

t[x]

.sand=t[x*2]

.sand&t[x*2+

1].sand;

}void

updata

(ll x,ll w)

void

downdata

(ll x)

ll ask

(ll x,ll l,ll r)

void

change

(ll x,ll l,ll r,ll val)

downdata

(x);

if(r<=t[x*2]

.r)change

(x*2

,l,r,val)

;else

if(l>=t[x*2+

1].l)change

(x*2+1

,l,r,val)

;else

change

(x*2

,l,t[x*2]

.r,val)

,change

(x*2+1

,t[x*2+

1].l,r,val)

; t[x]

.sor=t[x*2]

.sor|t[x*2+

1].sor;

t[x]

.sand=t[x*2]

.sand&t[x*2+

1].sand;

}}tree;

void

addl

(ll x,ll y)

void

dfs(ll x,ll fa)

}void

dfs2

(ll x,ll fa)

for(ll i=ls[x]

;i;i=a[i]

.next)

}void

push_change

(ll x,ll y,ll z)

if(dep[x]

>dep[y]

)swap

(x,y)

; tree.

change(1

,seg[x]

,seg[y]

,z);

return;}

ll push_ask

(ll x,ll y)

if(dep[x]

>dep[y]

)swap

(x,y)

; ans|

=tree.

ask(

1,seg[x]

,seg[y]);

cnt+

=seg[y]

-seg[x]+1

;return ans*pow[cnt-1]

%xjq;

}int

main()

pow[0]

=1;for

(ll i=

1;i<=n;i++

) pow[i]

=(pow[i-1]

*2)%xjq;

for(ll i=

1;i<=n;i++

)scanf

("%lld"

,&w[i]);

dfs(1,

0);top[1]

=1;dfs2(1

,0);

tree.

build(1

,1,n);

for(ll i=

1;i<=m;i++

)}

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

多組詢問,每次把樹上的一條簡單路徑中的點權扔入集合中,求該集合的子異和,子異和定義為所有非空子集的異或和的和,而且需要支援區間異或 考慮某一位滿足異或和為1的子集數,若設異或某一位為k kk為1的數量為h kh k hk 那麼結果應為cnt k 2n hk i 1 hk2 c n 2i 1 2 n ...

QTREE 子杰樹 線段樹 樹鏈剖分

題解 樹鏈剖分的模板題,我早就寫過了,但長時間沒做樹剖的題目,這個模板已經忘得差不多了,今天再做用來複習樹剖,順便卡卡常數。include include include include include include includeusing namespace std define file r...

樹鏈剖分 P3384 模板 樹鏈剖分

題目描述 戳這裡 題解 其實樹剖的重點就在於輕重鏈,這篇文章寫的很好 然而我線段樹寫得全是問題,改了半天2333 如下 include include include using namespace std const int maxn 100005 int n,m,root,tt,tot,lnk ...