生活随笔
收集整理的這篇文章主要介紹了
2021牛客暑期多校训练营4 E - Tree Xor 线段树 + 拆分区间
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
傳送門
文章目錄
題意:
給你一棵樹(shù),每個(gè)點(diǎn)原本都有一個(gè)權(quán)值wiw_iwi?,但是你只知道相鄰兩個(gè)點(diǎn)之間的wu⊕wvw_u\oplus w_vwu?⊕wv?,問(wèn)你有多少種w1,2,...,nw_{1,2,...,n}w1,2,...,n?
n≤1e5,wi<230n\le1e5,w_i<2^{30}n≤1e5,wi?<230
思路:
顯然我們?nèi)绻_定了一個(gè)點(diǎn)的權(quán)值,那么其他的點(diǎn)都就確定了。
更具體的是,我們可以求出111到其他點(diǎn)之間的w1⊕wxw_1\oplus w_xw1?⊕wx?,其中我們可以假設(shè)w1=0w_1=0w1?=0,那么當(dāng)給w1⊕aw_1\oplus aw1?⊕a時(shí),就相當(dāng)于將其他w2,3,...,n⊕aw_{2,3,...,n}\oplus aw2,3,...,n?⊕a,所以我們問(wèn)題就轉(zhuǎn)換成了對(duì)于每個(gè)區(qū)間求合法的aaa使得li≤wi⊕a≤ril_i\le w_i\oplus a\le r_ili?≤wi?⊕a≤ri?,轉(zhuǎn)換一下就是wi⊕[li,ri]w_i\oplus [l_i,r_i]wi?⊕[li?,ri?]的合法區(qū)間。這個(gè)區(qū)間肯定不是連續(xù)的,所以考慮將其拆分成若干區(qū)間。
由于拆分的區(qū)間肯定不能很多,所以考慮用二進(jìn)制來(lái)拆分這個(gè)區(qū)間。考慮這樣一種形式的二進(jìn)制區(qū)間[xxxx0000,xxxx1111][xxxx0000,xxxx1111][xxxx0000,xxxx1111],其中xxx表示可以是任意數(shù),但是兩個(gè)的xxx對(duì)應(yīng)位置必須相同。這樣的區(qū)間滿足其異或上wiw_iwi?仍是一段連續(xù)的區(qū)間。我們驚奇的發(fā)現(xiàn),這個(gè)區(qū)間后半部分不正是線段樹(shù)的每段區(qū)間嗎?所以考慮建一棵[0,230?1][0,2^{30}-1][0,230?1]的線段樹(shù),將這個(gè)區(qū)間插入,可知最多能被分成lognlognlogn段區(qū)間。當(dāng)這個(gè)區(qū)間被完全包含的時(shí)候,我們打一個(gè)懶標(biāo)記即可。
查詢的時(shí)候如果懶標(biāo)記=n=n=n的時(shí)候,就直接返回區(qū)間長(zhǎng)度即可。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=5000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,w
[N
],p
[N
];
int l
[N
],r
[N
],idx
;
struct Node {int l
,r
;int cnt
,lazy
;
}tr
[N
<<2];
vector
<PII
>v
[N
];void dfs(int u
,int fa
) {for(auto x
:v
[u
]) {if(x
.X
==fa
) continue;w
[x
.X
]=w
[u
]^x
.Y
;dfs(x
.X
,u
);}
}int newnode() {int u
=++idx
;tr
[u
].l
=tr
[u
].r
=0;tr
[u
].cnt
=tr
[u
].lazy
=0;return u
;
}void insert(int &u
,int l
,int r
,int ql
,int qr
,int w
,int dep
) {if(!u
) u
=newnode();int nl
=(l
^w
)&(((1<<30)-1)^((1<<(dep
+1))-1));int nr
=(l
^w
)|((1<<(dep
+1))-1);if(nl
>=ql
&&nr
<=qr
) {tr
[u
].lazy
++;tr
[u
].cnt
++;return;}if(tr
[u
].cnt
) {if(!tr
[u
].l
) tr
[u
].l
=newnode();if(!tr
[u
].r
) tr
[u
].r
=newnode();tr
[tr
[u
].l
].cnt
+=tr
[u
].cnt
; tr
[tr
[u
].r
].cnt
+=tr
[u
].cnt
;tr
[u
].cnt
=0;}int mid
=(l
+r
)>>1;int ll
=(l
^w
)&(((1<<30)-1)^((1<<(dep
))-1)),lr
=(l
^w
)|((1<<(dep
))-1);int rl
=(r
^w
)&(((1<<30)-1)^((1<<(dep
))-1)),rr
=(r
^w
)|((1<<(dep
))-1);if(w
>>dep
&1) {if(ql
<=rr
) insert(tr
[u
].r
,mid
+1,r
,ql
,qr
,w
,dep
-1);if(qr
>=ll
) insert(tr
[u
].l
,l
,mid
,ql
,qr
,w
,dep
-1);} else {if(ql
<=lr
) insert(tr
[u
].l
,l
,mid
,ql
,qr
,w
,dep
-1);if(qr
>=rl
) insert(tr
[u
].r
,mid
+1,r
,ql
,qr
,w
,dep
-1);}
}int query(int u
,int l
,int r
) {if(!u
) return 0;if(tr
[u
].cnt
==n
) return r
-l
+1;if(tr
[u
].cnt
) {if(tr
[u
].l
) tr
[tr
[u
].l
].cnt
+=tr
[u
].cnt
;if(tr
[u
].r
) tr
[tr
[u
].r
].cnt
+=tr
[u
].cnt
;tr
[u
].cnt
=0;}int ans
=0,mid
=(l
+r
)>>1;ans
+=query(tr
[u
].l
,l
,mid
);ans
+=query(tr
[u
].r
,mid
+1,r
);return ans
;
}int main()
{
scanf("%d",&n
);for(int i
=1;i
<=n
;i
++) scanf("%d%d",&l
[i
],&r
[i
]);for(int i
=1;i
<=n
-1;i
++) {int a
,b
,c
; scanf("%d%d%d",&a
,&b
,&c
);v
[a
].pb({b
,c
}); v
[b
].pb({a
,c
});}dfs(1,0); int rt
=newnode();int limit
=(1<<30)-1;for(int i
=1;i
<=n
;i
++) {insert(rt
,0,limit
,l
[i
],r
[i
],w
[i
],29);}printf("%d\n",query(1,0,limit
));return 0;
}
總結(jié)
以上是生活随笔為你收集整理的2021牛客暑期多校训练营4 E - Tree Xor 线段树 + 拆分区间的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。