bzoj1858: [Scoi2010]序列操作(线段树)

4人阅读 评论(0) 收藏 举报
分类:

题目传送门

解法:
线段树。
因为01要交换。
所以0和1的信息都要维护。
维护最长连续一段,总数,从左端点连续,从右端点连续。
然后打上覆盖和翻转标记。
不允许两种标记同时存在。

如果要打覆盖标记,那么翻转标记就没用了。
如果打翻转标记,那么覆盖标记取反就行。

代码实现:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
struct node {int l,r,lc,rc,c[2],s[2],Lc[2],Rc[2],size,lazy,fz;}tr[210000];int trlen;
void bt(int l,int r) {
    int now=++trlen;tr[now].l=l;tr[now].r=r;tr[now].lc=tr[now].rc=-1;
    tr[now].c[1]=tr[now].c[0]=0;tr[now].s[1]=tr[now].s[0]=0;
    tr[now].Lc[0]=tr[now].Lc[1]=0;tr[now].Rc[0]=tr[now].Rc[1]=0;
    tr[now].size=r-l+1;tr[now].lazy=-1;tr[now].fz=0;
    if(l<r) {int mid=(l+r)/2;tr[now].lc=trlen+1;bt(l,mid);tr[now].rc=trlen+1;bt(mid+1,r);}
}
void update(int now) {
    int lc=tr[now].lc,rc=tr[now].rc;if(lc==-1)return ;
    if(tr[now].lazy!=-1) {
        int t=tr[now].lazy;
        tr[lc].c[t]=tr[lc].size;tr[rc].c[t]=tr[rc].size;
        tr[lc].c[1-t]=tr[rc].c[1-t]=0;
        tr[lc].Lc[t]=tr[lc].Rc[t]=tr[lc].size;
        tr[rc].Lc[t]=tr[rc].Rc[t]=tr[rc].size;
        tr[lc].Lc[1-t]=tr[lc].Rc[1-t]=0;
        tr[rc].Lc[1-t]=tr[rc].Rc[1-t]=0;
        tr[lc].s[t]=tr[lc].size;tr[lc].s[1-t]=0;
        tr[rc].s[t]=tr[rc].size;tr[rc].s[1-t]=0;
        tr[lc].fz=tr[rc].fz=0;tr[lc].lazy=tr[rc].lazy=tr[now].lazy;tr[now].lazy=-1;
    }if(tr[now].fz!=0) {
        swap(tr[lc].c[0],tr[lc].c[1]);swap(tr[rc].c[0],tr[rc].c[1]);
        swap(tr[lc].s[0],tr[lc].s[1]);swap(tr[rc].s[0],tr[rc].s[1]);
        swap(tr[lc].Lc[0],tr[lc].Lc[1]);swap(tr[rc].Lc[0],tr[rc].Lc[1]);
        swap(tr[lc].Rc[0],tr[lc].Rc[1]);swap(tr[rc].Rc[0],tr[rc].Rc[1]);
        tr[lc].fz^=1;tr[rc].fz^=1;tr[now].fz=0;
        if(tr[lc].fz==1&&tr[lc].lazy!=-1){tr[lc].lazy^=1;tr[lc].fz=0;}
        if(tr[rc].fz==1&&tr[rc].lazy!=-1){tr[rc].lazy^=1;tr[rc].fz=0;}
    }
}
void change(int now,int l,int r,int k) {
    update(now);
    if(tr[now].l==l&&tr[now].r==r) {
        tr[now].c[k]=tr[now].size;tr[now].c[1-k]=0;
        tr[now].s[k]=tr[now].size;tr[now].s[1-k]=0;
        tr[now].Lc[k]=tr[now].Rc[k]=tr[now].size;
        tr[now].Lc[1-k]=tr[now].Rc[1-k]=0;
        tr[now].lazy=k;tr[now].fz=0;return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)change(lc,l,r,k);else if(l>mid)change(rc,l,r,k);
    else {change(lc,l,mid,k);change(rc,mid+1,r,k);}
    for(int i=0;i<=1;i++) {
        tr[now].s[i]=tr[lc].s[i]+tr[rc].s[i];
        if(tr[lc].Lc[i]==tr[lc].size)tr[now].Lc[i]=tr[lc].size+tr[rc].Lc[i];
        else tr[now].Lc[i]=tr[lc].Lc[i];
        if(tr[rc].Rc[i]==tr[rc].size)tr[now]. Rc[i]=tr[rc].size+tr[lc].Rc[i];
        else tr[now].Rc[i]=tr[rc].Rc[i];
        tr[now].c[i]=max(max(tr[lc].c[i],tr[rc].c[i]),tr[lc].Rc[i]+tr[rc].Lc[i]);
    }
}
void fz(int now,int l,int r) {
    update(now);
    if(tr[now].l==l&&tr[now].r==r) {
        swap(tr[now].c[0],tr[now].c[1]);swap(tr[now].s[0],tr[now].s[1]);
        swap(tr[now].Lc[0],tr[now].Lc[1]);swap(tr[now].Rc[0],tr[now].Rc[1]);
        tr[now].fz^=1;if(tr[now].lazy!=-1&&tr[now].fz==1)tr[now].lazy^=1,tr[now].fz=0;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)fz(lc,l,r);else if(l>mid)fz(rc,l,r);
    else {fz(lc,l,mid);fz(rc,mid+1,r);}
    for(int i=0;i<=1;i++) {
        tr[now].s[i]=tr[lc].s[i]+tr[rc].s[i];
        if(tr[lc].Lc[i]==tr[lc].size)tr[now].Lc[i]=tr[lc].size+tr[rc].Lc[i];
        else tr[now].Lc[i]=tr[lc].Lc[i];
        if(tr[rc].Rc[i]==tr[rc].size)tr[now].Rc[i]=tr[rc].size+tr[lc].Rc[i];
        else tr[now].Rc[i]=tr[rc].Rc[i];
        tr[now].c[i]=max(max(tr[lc].c[i],tr[rc].c[i]),tr[lc].Rc[i]+tr[rc].Lc[i]);
    }
}
int find_sum(int now,int l,int r,int k) {
    update(now);
    if(tr[now].l==l&&tr[now].r==r)return tr[now].s[k];
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)return find_sum(lc,l,r,k);else if(l>mid)return find_sum(rc,l,r,k);
    else return find_sum(lc,l,mid,k)+find_sum(rc,mid+1,r,k);
}
int find_max(int now,int l,int r,int k) {
    update(now);
    if(tr[now].l==l&&tr[now].r==r)return tr[now].c[k];
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)return find_max(lc,l,r,k);else if(l>mid)return find_max(rc,l,r,k);
    else {
        int t=max(find_max(lc,l,mid,k),find_max(rc,mid+1,r,k));
        int tt=min(tr[lc].Rc[k],mid-l+1)+min(tr[rc].Lc[k],r-mid);
        return max(tt,t);
    }
}
int main() {
    //freopen("1858.in","r",stdin);freopen("1858.out","w",stdout); 
    int n,m;scanf("%d%d",&n,&m);trlen=0;bt(1,n);
    for(int i=1;i<=n;i++) {int k;scanf("%d",&k);change(1,i,i,k);}
    while(m--) {
        int t,x,y;scanf("%d%d%d",&t,&x,&y);x++;y++;
        if(t<=1)change(1,x,y,t);
        else if(t==2)fz(1,x,y);
        else if(t==3)printf("%d\n",find_sum(1,x,y,1));
        else printf("%d\n",find_max(1,x,y,1));
    }
    return 0;
}
查看评论

bzoj1858【scoi2010】序列操作

很麻烦的线段树模板
  • AaronGZK
  • AaronGZK
  • 2015-11-08 22:11:27
  • 628

BZOJ 1858 [Scoi2010]序列操作 线段树

BZOJ 1858 [Scoi2010]序列操作 线段树
  • wzq_QwQ
  • wzq_QwQ
  • 2015-09-24 07:55:15
  • 1645

[BZOJ1858]SCOI2010序列操作|线段树

一看以为是线段树水题,写起来发现好像询问4比较麻烦,调了好久。。 对每个线段树节点维护sum为区间内1的个数,ml0、mr0表示左右的最长连续0长度,ml1,mr1同理,m0、m1为区间内连续0/1的...
  • Tag_king
  • Tag_king
  • 2015-04-28 21:22:07
  • 886

BZOJ1858 [Scoi2010]序列操作

傻逼题…… 维护0和1的左最长右最长和最长还有和,打覆盖标和翻转标即可 #include #include #include #include #include #include #include...
  • neither_nor
  • neither_nor
  • 2016-08-17 13:54:30
  • 217

【BZOJ1858】[Scoi2010]序列操作【线段树】

【题目链接】 调了一早上,码力++。 大概跪了几个地方: pushdown里rx1手滑打成了rx0。 查询最大子段函数,区间合并忘了上传sum。 mx1合并时候直接写了赋值,忘了...
  • BraketBN
  • BraketBN
  • 2016-04-30 14:13:18
  • 440

【BZOJ1858】[Scoi2010]序列操作 线段树

线段树裸(shen)题…… 题意:
  • eolv99
  • eolv99
  • 2014-10-04 15:48:43
  • 651

bzoj1858

线段树模板题#include &amp;lt;cstdio&amp;gt; #include &amp;lt;iostream&amp;gt; using namespace std; int n,m...
  • leijp1430
  • leijp1430
  • 2016-03-09 17:41:18
  • 341

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

其实这道题用线段树神马的应该是可做的…… 但是鉴于我跪烂的位运算水平…… 我决定用位运算压常数水过去~~ (其实要是数据强的话我早就完了) 我一次又一次犯的,b错误耗费了我一下午的时间…… ...
  • ZMOIYNLP
  • ZMOIYNLP
  • 2015-03-10 21:08:26
  • 504

【bzoj 1858】 [Scoi2010]序列操作 线段树

第一次学习线段树的时候写的第一道题,想一想那时候天真的自己还是搞了一整天,用了将近标程2倍的代码量,记得那时候当屏幕出现ac是激动的样子,哎,人老了 #include #include #inclu...
  • pbihao
  • pbihao
  • 2016-10-16 20:25:43
  • 107

【SCOI2010】序列操作 线段树

题目描述   lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:   0 a b 把[a, b]区间内的所有数全变...
  • qq_25554407
  • qq_25554407
  • 2017-03-24 14:14:41
  • 180
    个人资料
    持之以恒
    等级:
    访问量: 1万+
    积分: 2350
    排名: 1万+
    博客专栏
    最新评论