zoukankan      html  css  js  c++  java
  • 【LOJ】#2492. 「BJOI2018」二进制

    题解

    每次开这样的数据结构题感想都大概是如下两点
    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('
    ')
    #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();
    }
    
  • 相关阅读:
    队列的实现
    前端的数据结构
    有关es6的模块化
    jQuery---事件的执行顺序
    短网址生成和还原工具使用教程
    【01】HTML_day01_03-HTML常用标签
    JS中变量、作用域的本质,定义及使用方法
    JS 重载父页面
    搞懂Nginx一篇文章就够了
    重复的子字符串
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9978952.html
Copyright © 2011-2022 走看看