UVALive 8518 - Sum of xor sum
UVALive 8518 - Sum of xor sum
做法:線段樹維護:答案,邊界在左端點的區(qū)間異或為1的個數(shù),邊界在右端點異或為1的個數(shù),1的個數(shù),區(qū)間長度,這樣已經(jīng)自洽了。(每次講線段樹,都會講這個題,比較經(jīng)典的思想)
----update:2018/10/09
首先,我們考慮拆位,分別計算每一位的貢獻然后合并出答案,現(xiàn)在序列的元素只包含0或1。我們希望用線段樹維護,異或為1的區(qū)間的個數(shù),即包含奇數(shù)個1的區(qū)間的個數(shù)。那么,假設(shè)現(xiàn)在已知,[L,mid]有多少個區(qū)間包含奇數(shù)個1,[mid+1,R]有多少個區(qū)間包含奇數(shù)個1,那么合并后的區(qū)間的答案,就是左邊的答案+右邊的答案+橫跨兩個區(qū)間的答案。
橫跨兩個區(qū)間的答案 = (左邊以mid為右端點包含奇數(shù)個1的區(qū)間的數(shù)目) * (右邊以(mid+1)為左端點包含偶數(shù)個1的區(qū)間的數(shù)目) + (左邊以mid為右端點包含偶數(shù)個1的區(qū)間的數(shù)目) * (右邊以(mid+1)為左端點包含奇數(shù)個1的區(qū)間的數(shù)目)
那么現(xiàn)在就需要我們維護上邊這4個東西,顯然如果知道奇數(shù)的貢獻,就很容易可以計算出偶數(shù)貢獻。所以實際只用維護2個東西。這兩個東西也可以用類似的思想維護出來,所以我們不用維護其他的東西了。引用大佬的話:“這類題目就是需要什么維護什么,直到數(shù)據(jù)結(jié)構(gòu)自洽”當(dāng)然,如果發(fā)現(xiàn)需要維護的東西過多,就要考慮換個思路了。
#include <bits/stdc++.h> #define pb push_back typedef long long ll; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f3f; const int mod = 1e9 + 7; using namespace std; int T, n, q, a[N]; struct node{ll ans[20], lx[20], rx[20];int num[20], len; } tree[N<<2]; node mer(node &a,node &b) {node res;for(int i = 0; i < 20; ++i) {res.ans[i] = a.ans[i] + b.ans[i];res.ans[i] += a.lx[i]*(b.len - b.rx[i]);res.ans[i] += (a.len - a.lx[i])*b.rx[i];if(b.num[i] & 1) res.lx[i] = b.lx[i] + (a.len - a.lx[i]);else res.lx[i] = b.lx[i] + a.lx[i];if(a.num[i] & 1) res.rx[i] = a.rx[i] + (b.len - b.rx[i]);else res.rx[i] = a.rx[i] + b.rx[i];res.num[i] = a.num[i] + b.num[i];}res.len = a.len + b.len;return res; } void build(int p, int l, int r) {if(l == r) {tree[p].len = 1;for(int i = 0; i < 20; ++i)if( a[l] & (1<<i) ) tree[p].ans[i] = tree[p].lx[i] = tree[p].rx[i] = tree[p].num[i] = 1;else tree[p].ans[i] = tree[p].lx[i] = tree[p].rx[i] = tree[p].num[i] = 0;return;}int mid = (l + r) >> 1;build(p<<1, l, mid); build(p<<1|1, mid+1, r);tree[p] = mer(tree[p<<1],tree[p<<1|1]); } node ask(int p,int l,int r,int L,int R) {if(l == L && R == r) {return tree[p];}int mid = (l + r) >> 1;if(R <= mid) return ask(p<<1,l,mid,L,R);else if(L > mid) return ask(p<<1|1,mid+1,r,L,R);else {node tmp1 = ask(p<<1,l,mid,L,mid);node tmp2 = ask(p<<1|1,mid+1,r,mid+1,R);return mer(tmp1,tmp2);} } int main() {scanf("%d", &T);while( T-- ) {scanf("%d%d",&n,&q);for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);build(1,1,n);while(q--) { int l, r;scanf("%d %d",&l,&r);node tmp = ask(1,1,n,l,r);ll ans = 0;for(int i = 19; i >= 0; --i) ans = ((ans<<1LL)%mod + tmp.ans[i])%mod;printf("%lld\n",ans);}}return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/RRRR-wys/p/9749591.html
總結(jié)
以上是生活随笔為你收集整理的UVALive 8518 - Sum of xor sum的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓平板电脑的方向该这样安卓平板电脑的方
- 下一篇: 电脑中病毒后应该如何自救电脑中病毒了如何