[TJOI2009] 开关

题目链接

线段树其实就行了
试一下分块

但很奇怪TLE了
调到200才A

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define MAXN 150005

int N,M;

struct BLOCK {
    int drop[MAXN],sum[MAXN],num[MAXN],block;

    inline void init() {
        block = sqrt(N)>200?200:sqrt(N);
        for(int i=0;i<N;++i) drop[i] = sum[i] = 0;
    }
    inline void reset(int k) {
        sum[k] = 0;
        for(int i=k*block;i<=min(N-1,block*(k+1)-1);++i) {
            drop[i] = (num[k]&1)?(drop[i]^1):drop[i];
            if(drop[i]) sum[k] ++;
        }
        num[k] = 0;
    }

    inline void update(int l,int r) {
        l--; r--;
        reset(l/block);
        for(;l<=r&&l%block;++l) {
            drop[l] ^= 1;
            if(drop[l]) sum[l/block] ++;
            else sum[l/block] --;
        }

        for(;l+block-1<=r;l+=block) {
            num[l/block] ++; sum[l/block] = block - sum[l/block];
        }
        
        if(l<=r) reset(r/block);
        for(;l<=r;++l) {
            drop[l] ^= 1;
            if(drop[l]) sum[l/block] ++;
            else sum[l/block] --;
        }
    }
    inline int query(int l,int r) {
        l--; r--;
        int ans = 0; reset(l/block);
        for(;l<=r&&l%block;++l)
            if(drop[l]) ans ++;
        for(;l+block-1<=r;l+=block)
            ans += sum[l/block];
        if(l<=r) reset(r/block);
        for(;l<=r;++l)
            if(drop[l]) ans ++;
        return ans;
    }

} B;

int main() {

    cin >> N >> M; B.init();
    for(int i=1;i<=M;++i) {
        int opt ,l,r;
        cin >> opt >> l >> r;
        if(opt==0) B.update(l,r);
        else cout << B.query(l,r) << "\n";
    }
}
posted @ 2021-11-04 11:09  Neworld1111  阅读(21)  评论(0编辑  收藏  举报