【LOJ】#2492. 「BJOI2018」二進位制
阿新 • • 發佈:2018-11-19
題解
每次開這樣的資料結構題感想都大概是如下兩點
1.為什麼別人程式碼長度都是我的1/2????
2.為什麼我執行時間都是他們的兩倍????
簡單分析一下,我們關注一個區間是否合法只關注這個區間有多少個1,有多少個0
有偶數個1,一定合法,因為3的二進位制是11,我們只需要111111拼起來一定除得開3
只有一個1,一定不合法,因為必然質因數只有2
有奇數個且大於一個1,沒有0,一定不合法,我們兩兩消掉11,最後會剩下一個除不開的1
有奇數個且大於一個1,有一個0,一定不合法,我們兩兩消掉11,最後會剩下一個10或者01,也除不開
有奇數個且大於一個1,有兩個0,一定合法,10101是一個合法的,剩下的兩兩消掉11即可
分析完了想怎麼維護吧,反著比正著好維護,就考慮用總方案數減掉只有一個1的區間,和有奇數個且大於1個1而且0的個數小於2個的區間
分析了完了就是分類討論大題了= =
先討論第一種
我現在有線段樹上左右兩個區間
左邊是
010001000
右邊是
001000100
我顯然要用右邊的[1,2]和左邊的[3,6]搭配,右邊的[3,6]和左邊的[7,10]搭配
所以我們維護每個區間最靠左的兩個1的下標,最靠右的兩個1的下標,剩下的小情況就討論一下好了
有奇數個且大於1個1而且0的個數小於2的個數
左邊是
1101101111
1111011101
我要用右邊的[1,4]和左邊[7,10]搭配,且1的個數有奇數個
還有右邊[1,4]和左邊[4,6]搭配,1的個數有奇數個
右邊[5,8]和左邊[7,10]搭配,1的個數有奇數個
我們每段右區間搭配的時候顯然相鄰兩個會佔另一半區間的所有,所以最後如果右邊區間長度是奇數分類討論一下就好
題解
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define space putchar(' ') #define enter putchar('\n') #define mp make_pair #define MAXN 100005 #define pb push_back //#define ivorysi using namespace std; typedef long long int64; typedef unsigned int u32; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {putchar('-');x = -x;} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N,M; int a[MAXN]; struct node { int L,R; pii l[2],r[2]; int64 sum[2]; }tr[MAXN * 4]; void update(int u); int64 Query0(int u,int l,int r,pii &zero); int64 Query1(int u,int l,int r,pii &one); void build(int u,int l,int r); void check(pii &t,int v,int op) { if(op == 0) { if(v < t.se) t.se = v; if(t.se < t.fi) swap(t.fi,t.se); } else { if(v > t.se) t.se = v; if(t.se > t.fi) swap(t.fi,t.se); } } void update(int u) { for(int i = 0 ; i <= 1 ; ++i) tr[u].sum[i] = tr[u << 1].sum[i]; int mid = (tr[u].L + tr[u].R) >> 1; pii t; t = tr[u << 1].r[0];tr[u].sum[0] += Query0(u << 1 | 1,mid + 1,tr[u].R,t); t = tr[u << 1].r[1];tr[u].sum[1] += Query1(u << 1 | 1,mid + 1,tr[u].R,t); for(int i = 0 ; i <= 1 ; ++i) { tr[u].l[i] = mp(tr[u].R + 1,tr[u].R + 1); tr[u].r[i] = mp(tr[u].L - 1,tr[u].L - 1); if(tr[u << 1].l[i].fi <= mid) check(tr[u].l[i],tr[u << 1].l[i].fi,0); if(tr[u << 1].l[i].se <= mid) check(tr[u].l[i],tr[u << 1].l[i].se,0); check(tr[u].l[i],tr[u << 1 | 1].l[i].fi,0); check(tr[u].l[i],tr[u << 1 | 1].l[i].se,0); if(tr[u << 1 | 1].r[i].fi > mid) check(tr[u].r[i],tr[u << 1 | 1].r[i].fi,1); if(tr[u << 1 | 1].r[i].se > mid) check(tr[u].r[i],tr[u << 1 | 1].r[i].se,1); check(tr[u].r[i],tr[u << 1].r[i].fi,1); check(tr[u].r[i],tr[u << 1].r[i].se,1); } } int64 Query1(int u,int l,int r,pii &one) { if(tr[u].L == l && tr[u].R == r) { int64 res = 0; if(l < tr[u].l[1].fi) { res += (tr[u].l[1].fi - l) * (one.fi - one.se); } if(tr[u].l[1].fi < tr[u].l[1].se){ res += (tr[u].l[1].se - tr[u].l[1].fi) * (l - 1 - one.fi); } if(tr[u].r[1].fi >= l) check(one,tr[u].r[1].fi,1); if(tr[u].r[1].se >= l) check(one,tr[u].r[1].se,1); return res + tr[u].sum[1]; } int mid = (tr[u].L + tr[u].R) >> 1; if(r <= mid) return Query1(u << 1,l,r,one); else if(l > mid) return Query1(u << 1 | 1,l,r,one); else return Query1(u << 1,l,mid,one) + Query1(u << 1 | 1,mid + 1,r,one); } int up(int A,int B) { if(A % B == 0) return A / B; return A / B + 1; } int64 Query0(int u,int l,int r,pii &zero) { if(tr[u].L == l && tr[u].R == r) { int64 res = 0; if(l < tr[u].l[0].fi) { int t = tr[u].l[0].fi - l; if(l - 1 > zero.fi) { res += t / 2 * (l - 1 - zero.fi); if(t & 1) { res += (l - 1 - zero.fi) / 2; } } if(zero.fi > zero.se) { res += t / 2 * (zero.fi - zero.se - 1); if(t & 1) { if(l - 1 - zero.fi & 1) res += up(zero.fi - zero.se - 1,2); else res += (zero.fi - zero.se - 1) / 2; } if(l - 1 - zero.fi & 1) res += t / 2; else res += up(t,2); if(zero.fi == l - 1) --res; } } if(tr[u].l[0].fi < tr[u].l[0].se) { int t = tr[u].l[0].se - tr[u].l[0].fi; if(l - 1 > zero.fi) { res += t / 2 * (l - 1 - zero.fi); if(tr[u].l[0].fi == l) --res; if(t & 1) { if(tr[u].l[0].se - l - 1 & 1) res += (l - 1 - zero.fi) / 2; else res += up(l - 1 - zero.fi,2); } } } if(tr[u].r[0].fi >= l) check(zero,tr[u].r[0].fi,1); if(tr[u].r[0].se >= l) check(zero,tr[u].r[0].se,1); return res + tr[u].sum[0]; } int mid = (tr[u].L + tr[u].R) >> 1; if(r <= mid) return Query0(u << 1,l,r,zero); else if(l > mid) return Query0(u << 1 | 1,l,r,zero); else return Query0(u << 1,l,mid,zero) + Query0(u << 1 | 1,mid + 1,r,zero); } void build(int u,int l,int r) { tr[u].L = l;tr[u].R = r; tr[u].sum[0] = tr[u].sum[1] = 0; if(l == r) { for(int i = 0 ; i <= 1 ; ++i) { tr[u].l[i] = mp(r + 1,r + 1); tr[u].r[i] = mp(l - 1,l - 1); if(a[l] == i) { check(tr[u].l[i],l,0); check(tr[u].r[i],l,1); } } if(a[l] == 1) tr[u].sum[1] = 1; return; } int mid = (l + r) >> 1; build(u << 1,l,mid); build(u << 1 | 1,mid + 1,r); update(u); } void Change(int u,int pos) { if(tr[u].L == tr[u].R) { tr[u].sum[0] = tr[u].sum[1] = 0; for(int i = 0 ; i <= 1 ; ++i) { tr[u].l[i] = mp(pos + 1,pos + 1); tr[u].r[i] = mp(pos - 1,pos - 1); if(a[pos] == i) { check(tr[u].l[i],pos,0); check(tr[u].r[i],pos,1); } } if(a[pos] == 1) tr[u].sum[1] = 1; return; } int mid = (tr[u].L + tr[u].R) >> 1; if(pos <= mid) Change(u << 1,pos); else Change(u << 1 | 1,pos); update(u); } void Solve() { read(N); for(int i = 1 ; i <= N ; ++i) read(a[i]); build(1,1,N); read(M); int op,l,r; for(int i = 1 ; i <= M ; ++i) { read(op);read(l); if(op == 1) { a[l] ^= 1;Change(1,l); } else { read(r); int64 res = 1LL * (r - l + 1) * (r - l + 2) / 2; pii t; res -= Query0(1,l,r,t = mp(l - 1,l - 1)); res -= Query1(1,l,r,t = mp(l - 1,l - 1)); out(res);enter; } } } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }