分块&&莫队学习笔记

坑太大了,一时甚至填不起来(现在只填到分块)


分块和莫队都是非常好的暴力算法,

能够让人在面对一些要求维护特殊序列的题时,可以拿到暴力高分甚至AC

甚至还多次出现在各地省选中,学了不亏的好东西

(但是还是要追求巧妙正解啊歪)


分块

分块,顾名思义,将数列切块,批量每个块上的答案信息,

询问时如果询问区间覆盖了这个块,直接统计答案信息就行了,如果没有,就把这个块暴力拆开,查询里面的具体数据。

修改时如果修改区间覆盖了这个块,给这个块打个标记,查询的时候再把标记处理给块内具体数据,如果不覆盖,就暴力拆开维护具体数据。

具体来看题。


Luogu P3870 [TJOI2009]开关

  • 有一个01序列,要求支持区间异或,区间查询的操作,强制在线。

  • 操作次数 = 序列长度 = 1e5

线段树,分块,朴素暴力都可以A

首先求出块长,然后求出块数,接着处理每个块的基本信息,然后小心维护就行了

分块细节很多,我调了一下午,这里说几个蒟蒻错了的地方

  • 打tag的时候已经处理了答案,消tag时又处理了一遍答案......

  • 没有处理区间在一个块内的情况

  • 循环的时候i就是块的下标,结果循环里面对下标又求了一次下标......

#include<bits/stdc++.h>

using namespace std ;

const int MAXN = 100010;
int n,m;
struct Block{
    int l,r;
    int ans,tag;
}blo[1000];
int fab[MAXN],a[MAXN],sq,bctr;

void set_up(){
    sq = sqrt(n);
    bctr = n/sq;
    if(n%sq) ++bctr;
//      cout<<sq<<"<-sq bctr->"<<bctr<<endl;
    for(int i=1;i<=n;i++){
        fab[i] = (i-1)/sq+1;
//          cout<<fab[i]<<" ";
    }
//      cout<<endl;
    for(int i=1;i<bctr;i++){
        blo[i].l = (i-1) * sq + 1;
        blo[i].r = i * sq; 
    }
    blo[bctr].l = (bctr-1) * sq + 1;
    blo[bctr].r = n;
//  for(int i=1;i<=bctr;i++){
//      cout<<"i = "<<i;
//      cout<<" ans = "<<blo[i].ans;
//      cout<<" tag = "<<blo[i].tag;
//      cout<<" l = "<<blo[i].l<<" r = "<<blo[i].r<<endl;
//  }
}

void pushdown(int x){//无脑push 
//  if(blo[x].tag == 0) cout<<"???"<<endl;
    for(int i=blo[x].l;i<=blo[x].r;i++)
        a[i] ^= 1;
    blo[x].tag = 0;
}

void change (int x,int y){
    if(fab[x] == fab[y]){
        if(blo[fab[x]].tag) pushdown(fab[x]);
        for(int i=x;i<=y;i++){
            a[i] ^= 1;
            blo[fab[i]].ans += ((a[i] == 1) ? 1 : -1); 
        }
        return;
    }
/*-----------same block--------*/ 
    if(blo[fab[x]].l != x){
        if(blo[fab[x]].tag) pushdown(fab[x]);
        for(int i=x;i<=blo[fab[x]].r;i++){
            a[i] ^= 1;
            blo[fab[i]].ans += (a[i] == 1) ? 1 : -1;
        }
    }
    else {
        blo[fab[x]].tag ^= 1;
        blo[fab[x]].ans = (blo[fab[x]].r - blo[fab[x]].l + 1) - blo[fab[x]].ans;
    }
/*-----------left part---------*/
    if(blo[fab[y]].r != y){
        if(blo[fab[y]].tag) pushdown(fab[y]);
        for(int i=blo[fab[y]].l;i<=y;i++){
            a[i] ^= 1;
            blo[fab[y]].ans += (a[i] == 1) ? 1 : -1;
        }
    }
    else{
        blo[fab[y]].tag ^= 1;
        blo[fab[y]].ans = (blo[fab[y]].r - blo[fab[y]].l + 1) - blo[fab[y]].ans;
    }
/*-----------right part---------*/
    for(int i=fab[x]+1;i<=fab[y]-1;i++){
        blo[i].tag ^= 1;
        blo[i].ans = (blo[i].r - blo[i].l + 1) - blo[i].ans;
    }
//  for(int i=1;i<=bctr;i++){
//      cout<<blo[i].ans<<" ";
//  }
    
    return;
/*-----------middle part--------*/
}

int ask(int x,int y){
    int ret = 0;
    
//      for(int i=1;i<=bctr;i++){
//          cout<<blo[i].ans<<" ";
//      }
    
    if(fab[x] == fab[y]){
        if(blo[fab[x]].tag) pushdown(fab[x]);
        for(int i=x;i<=y;i++){
            ret += a[i];
        }
        return ret;
    }
    
    if(x != blo[fab[x]].l) {
        if(blo[fab[x]].tag) pushdown(fab[x]);
        for(int i = x; i <= blo[fab[x]].r; i++) {
            ret += a[i];
        }
    }
    else ret += blo[fab[x]].ans;
    
//      for(int i=1;i<=bctr;i++){
//          cout<<blo[i].ans<<" ";
//      }
    
    if(y != blo[fab[y]].r) {
        if(blo[fab[y]].tag) pushdown(fab[y]);
        for(int i = blo[fab[y]].l; i <= y; i++) {
            ret += a[i];
        }
    }
    else ret += blo[fab[y]].ans;
    
//      for(int i=1;i<=bctr;i++){
//          cout<<blo[i].ans<<" ";
//      }
    
    for(int i=fab[x]+1;i<=fab[y]-1;i++){
        ret += blo[i].ans;
//      cout<<"ret = "<<ret<<endl;
//      cout<<"i = "<<i<<endl;
//      cout<<"blo[i].ans = "<<blo[i].ans<<endl;
    }
    return ret;
}

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    set_up();
    for(int i=1;i<=m;i++){
        int t,x,y;
        cin>>t>>x>>y;
        if(t == 0){
            change(x,y);
        }
        if(t == 1){
            cout<<ask(x,y)<<endl;
        }
//      cout<<"for this round,the ans1 and ans2 and ans3 is "<<blo[1].ans<<" "<<blo[2].ans<<" "<<blo[3].ans<<endl;
    }
    return 0;
}

百万丢人调试信息

猜你喜欢

转载自www.cnblogs.com/SINXIII/p/11240348.html