【bzoj1858】【Scoi2010】序列操作【位运算】【卡常大法好】

其实这道题用线段树神马的应该是可做的……
但是鉴于我跪烂的位运算水平……
我决定用位运算压常数水过去~~
(其实要是数据强的话我早就完了)
我一次又一次犯的,b错误耗费了我一下午的时间……
这就是蒟蒻啊- -
一开始不知怎么回事,命令总是读不进去- -
然后发现~0U<<(r+1)有的时候不总是好用。

    printf("%u\n",~0U<<32);
    int r=32;
    printf("%u\n",~0U<<r);

这两条语句的输出结果一个是0,一个是4294967295……
所以为了避免这种悲催的情况,就把~0U << <script type="math/tex" id="MathJax-Element-41"><<</script>(r+1)改成~0U << <script type="math/tex" id="MathJax-Element-42"><<</script>r << <script type="math/tex" id="MathJax-Element-43"><<</script>1。
呵呵。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef unsigned int uint;
struct bitset{
    static const int maxlen=(100000>>5)+1;
    static const uint inf=~0U;
    uint d[maxlen];
    int list[65536];
    inline int cnt(uint x){
        return list[x&0xFFFF]+list[x>>16];
    }
    void Not(int l,int r){
        int l1=l>>5,r1=r>>5;
        l&=31;r&=31;
        d[l1]^=(1<<l)-1;
        d[r1]^=inf<<r<<1;
        for(;l1<=r1;++l1) d[l1]^=inf;
    }
    inline int count(int l,int r){
        int ans=0;
        int l1=l>>5,r1=r>>5;
        l&=31,r&=31;
        ans-=cnt(d[l1]&((1<<l)-1));
        ans-=cnt(d[r1]>>r>>1);
        for(;l1<=r1;++l1) ans+=cnt(d[l1]);
        return ans;
    }
    void clear(int l,int r){
        int l1=l>>5,r1=r>>5;
        l&=31,r&=31;
        if(l1==r1){d[l1]&=~((uint)(((1LL<<(r-l+1))-1)<<l));return;}
        d[l1]&=(1<<l)-1;
        d[r1]&=inf<<r<<1;
        for(++l1;l1<r1;++l1) d[l1]=0;        

    }
    void set(int l,int r){
        int l1=l>>5,r1=r>>5;
        l&=31,r&=31;
        if(l1==r1){d[l1]|=(uint)(((1LL<<(r-l+1))-1)<<l);return;}        
        d[l1]|=inf<<l;
        d[r1]|=(uint)((1LL<<r<<1)-1);
        for(++l1;l1<r1;++l1) d[l1]=inf;      
    }
    inline uint get(int pos){return (d[pos>>5]>>(pos&31))&1;}
}a;
inline int read(){
    int x=0;
    char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=x*10+ch-48,ch=getchar();
    return x;
}
int s[10];
void print(int x){
    if(x) s[0]=0;
    else s[0]=1,s[1]=0;
    while(x) s[++s[0]]=x%10,x/=10;
    while(s[0]) putchar(48+s[s[0]--]);
    putchar('\n');
}
int main(){
    for(int i=0;i<65536;++i) a.list[i]=a.list[i>>1]+(i&1);
    int n=read(),m=read();
    for(int i=0;i<n;++i)
        a.d[i>>5]|=(read()<<(i&31));//i&31!!!!
    while(m--){
        int opt=read(),x=read(),y=read();
        int ans,tmp;
        switch(opt){
            case 0:a.clear(x,y);break;
            case 1:a.set(x,y);break;
            case 2:a.Not(x,y);break;
            case 3:print(a.count(x,y));break;
            case 4:
                ans=0;tmp=0;
                for(int i=x;i<=y;++i){
                    if(a.get(i))tmp++;
                    else ans=max(ans,tmp),tmp=0;
                }
                print(max(ans,tmp));
                break;
        }
//      a.print();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值