P2572 [SCOI2010]序列操做 線段樹

  

題目描述

lxhgww最近收到了一個01序列,序列裏面包含了n個數,這些數要麼是0,要麼是1,如今對於這個序列有五種變換操做和詢問操做:c++

0 a b 把[a, b]區間內的全部數全變成0程序員

1 a b 把[a, b]區間內的全部數全變成1ide

2 a b 把[a,b]區間內的全部數所有取反,也就是說把全部的0變成1,把全部的1變成0ui

3 a b 詢問[a, b]區間內總共有多少個1spa

4 a b 詢問[a, b]區間內最多有多少個連續的1input

對於每一種詢問操做,lxhgww都須要給出回答,聰明的程序員們,大家能幫助他嗎?it

輸入輸出格式

輸入格式:class

 

輸入數據第一行包括2個數,n和m,分別表示序列的長度和操做數目date

第二行包括n個數,表示序列的初始狀態程序

接下來m行,每行3個數,op, a, b,(0<=op<=4,0<=a<=b<n)表示對於區間[a, b]執行標號爲op的操做

 

輸出格式:

 

對於每個詢問操做,輸出一行,包括1個數,表示其對應的答案

 

輸入輸出樣例

輸入樣例#1:  複製
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5

題目描述

lxhgww最近收到了一個01序列,序列裏面包含了n個數,這些數要麼是0,要麼是1,如今對於這個序列有五種變換操做和詢問操做:

0 a b 把[a, b]區間內的全部數全變成0

1 a b 把[a, b]區間內的全部數全變成1

2 a b 把[a,b]區間內的全部數所有取反,也就是說把全部的0變成1,把全部的1變成0

3 a b 詢問[a, b]區間內總共有多少個1

4 a b 詢問[a, b]區間內最多有多少個連續的1

對於每一種詢問操做,lxhgww都須要給出回答,聰明的程序員們,大家能幫助他嗎?

輸入輸出格式

輸入格式:

 

輸入數據第一行包括2個數,n和m,分別表示序列的長度和操做數目

第二行包括n個數,表示序列的初始狀態

接下來m行,每行3個數,op, a, b,(0<=op<=4,0<=a<=b<n)表示對於區間[a, b]執行標號爲op的操做

 

輸出格式:

 

對於每個詢問操做,輸出一行,包括1個數,表示其對應的答案

 

輸入輸出樣例

輸入樣例#1:  複製
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
輸出樣例#1:  複製
5
2
6
5


這些操做都比較簡單 以前都學過
可是加在一塊兒就會產生一個問題 那就是翻轉標記和區間修改標記的順序該如何處理 先反轉和先修改的操做是不同的


修改操做的優先級是比翻轉操做的優先級高的

在update裏
對一個點前後兩次操做一共有四種方法
1.先反轉後修改
顯然 翻轉的操做已經被覆蓋掉了 因此在設置修改懶標記的時候若是有翻轉標記直接清空掉

2.先修改後翻轉
正常處理

3.4沒有問題

在down裏
先處理修改的 由於修改的優先級高(先反轉後修改的操做已經被覆蓋掉了 也就是反轉標記已經被清零)
下推懶標記的時候若是下面的兩個兒子有翻轉標記的話要清空
而後處理翻轉標記便可


很是好的線段樹 加深了理解
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define pb push_back
#define inf 0x3f3f3f3f
#define lson l,m,pos<<1
#define rson m+1,r,pos<<1|1
#define CLR(A,v)  memset(A,v,sizeof A)
typedef pair<int,int>pii;
//////////////////////////////////
const int N=1e5+10;
int tsum[N<<2],t0[N<<2],t1[N<<2],ri0[N<<2],ri1[N<<2],le0[N<<2],le1[N<<2],len[N<<2],col[N<<2],rev[N<<2];
int num[N];
void up(int pos)
{
    tsum[pos]=tsum[pos<<1]+tsum[pos<<1|1];// 區間求和
    t0[pos]=max( max(t0[pos<<1],t0[pos<<1|1]),ri0[pos<<1]+le0[pos<<1|1]  );
    t1[pos]=max( max(t1[pos<<1],t1[pos<<1|1]),ri1[pos<<1]+le1[pos<<1|1]  );

    if(le1[pos<<1]==len[pos<<1])
    le1[pos]=le1[pos<<1]+le1[pos<<1|1];
    else le1[pos]=le1[pos<<1];

    if(le0[pos<<1]==len[pos<<1])
    le0[pos]=le0[pos<<1]+le0[pos<<1|1];
    else le0[pos]=le0[pos<<1];

    if(ri1[pos<<1|1]==len[pos<<1|1])
    ri1[pos]=ri1[pos<<1|1]+ri1[pos<<1];
    else ri1[pos]=ri1[pos<<1|1];

    if(ri0[pos<<1|1]==len[pos<<1|1])
    ri0[pos]=ri0[pos<<1|1]+ri0[pos<<1];
    else ri0[pos]=ri0[pos<<1|1];
}
void build(int l,int r,int pos)
{
    len[pos]=r-l+1;
    if(l==r){ tsum[pos]=num[l]; le0[pos]=ri0[pos]=t0[pos]=(num[l]==0);  le1[pos]=ri1[pos]=t1[pos]=(num[l]==1); return ;}
    int m=(l+r)>>1;build(lson);build(rson);up(pos);
}
void down(int m,int pos)
{
    if(col[pos]!=-1)// 修改會覆蓋翻轉
    {
        rev[pos<<1]=rev[pos<<1|1]=0;//覆蓋翻轉
        col[pos<<1]=col[pos<<1|1]=col[pos];//標記傳遞

        if(col[pos]==1){
        t1[pos<<1]=tsum[pos<<1]=le1[pos<<1]=ri1[pos<<1]=len[pos<<1];
        t1[pos<<1|1]=tsum[pos<<1|1]=le1[pos<<1|1]=ri1[pos<<1|1]=len[pos<<1|1];
        t0[pos<<1]=t0[pos<<1|1]=le0[pos<<1]=le0[pos<<1|1]=ri0[pos<<1]=ri0[pos<<1|1]=0;}
        else if(col[pos]==0){
        t0[pos<<1]=le0[pos<<1]=ri0[pos<<1]=len[pos<<1];
        t0[pos<<1|1]=le0[pos<<1|1]=ri0[pos<<1|1]=len[pos<<1|1];
        tsum[pos<<1]=tsum[pos<<1|1]=le1[pos<<1]=le1[pos<<1|1]=ri1[pos<<1]=ri1[pos<<1|1]=t1[pos<<1]=t1[pos<<1|1]=0;}
        
        col[pos]=-1;
    }
    if(rev[pos])
    {
        tsum[pos<<1]=len[pos<<1]-tsum[pos<<1];
        tsum[pos<<1|1]=len[pos<<1|1]-tsum[pos<<1|1];

        swap(le1[pos<<1],le0[pos<<1]);
        swap(le1[pos<<1|1],le0[pos<<1|1]);
        swap(ri1[pos<<1],ri0[pos<<1]);
        swap(ri1[pos<<1|1],ri0[pos<<1|1]);
        swap(t1[pos<<1],t0[pos<<1]);
        swap(t1[pos<<1|1],t0[pos<<1|1]);//翻轉01最大連續長度

        rev[pos<<1]^=1;rev[pos<<1|1]^=1;
        rev[pos]=0;
    }
}
void upsum(int L,int R,int v,int l,int r,int pos)
{
    if(L<=l&&r<=R)
    {
        col[pos]=v;rev[pos]=0;tsum[pos]=v*(r-l+1);
        t1[pos]=le1[pos]=ri1[pos]=v*(r-l+1);
        t0[pos]=le0[pos]=ri0[pos]=(v^1)*(r-l+1);
        return ;
    }int m=(l+r)>>1;down(r-l+1,pos);
    if(L<=m)upsum(L,R,v,lson);if(R>m)upsum(L,R,v,rson);up(pos);
}
void uprev(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R)
    {
        rev[pos]^=1;
        tsum[pos]=r-l+1-tsum[pos];
        swap(t1[pos],t0[pos]);
        swap(le1[pos],le0[pos]);
        swap(ri1[pos],ri0[pos]);
        return ;
    }int m=(l+r)>>1;down(r-l+1,pos);
    if(L<=m)uprev(L,R,lson);if(R>m)uprev(L,R,rson);up(pos);
}
int qsum(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R)return tsum[pos];
    int ans=0;int m=(l+r)>>1;down(r-l+1,pos);
    if(L<=m)ans+=qsum(L,R,lson);if(R>m)ans+=qsum(L,R,rson);
    return ans;
}
int qmax(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R)return t1[pos];
    int m=(l+r)>>1;
    down(r-l+1,pos);

    if(L<=m&&R>m)
    {
        int ans=max(qmax(L,R,lson),qmax(L,R,rson)),rm,lm;
        rm=min((m-L+1),ri1[pos<<1] );
        lm=min((R-m),le1[pos<<1|1]);
        ans=max(ans,rm+lm);return ans;
    }
    else if(L<=m)return qmax(L,R,lson);
    else if(R>m)return qmax(L,R,rson);
}
int n,m,a,b,c;
int main()
{
    CLR(col,-1);
    RII(n,m);
    rep(i,1,n)RI(num[i]);

    build(1,n,1);
    while(m--)
    {
        RIII(c,a,b);a++,b++;
        if(c==0)upsum(a,b,0,1,n,1);
        if(c==1)upsum(a,b,1,1,n,1);
        if(c==2)uprev(a,b,1,n,1);
        if(c==3)printf("%d\n",qsum(a,b,1,n,1));
        if(c==4)printf("%d\n",qmax(a,b,1,n,1));
    }
    return 0;
}
View Code

 









































0 5 6 3 3 9
輸出樣例#1:  複製
5
2
6
5
相關文章
相關標籤/搜索