bzoj1858: [Scoi2010]序列操作(線段樹)
題目傳送門
。
解法:
線段樹。
因為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;
}
相關文章
- NC20279 [SCOI2010]序列操作
- HDU 3333 Turing Tree(線段樹+離線操作)
- Transformation HDU - 4578線段樹綜合操作ORM
- 線段樹(3)——區間操作疊加
- CF EDU165-E-序列問題,線段樹
- 線~段~樹
- 線段樹
- 線段樹模板
- 線段樹--RMQMQ
- 01 線段樹
- 線段樹 hate it
- 【模版】線段樹
- ut.cpp 最大線段並減線段交 [線段樹]
- 權值線段樹
- 線段樹筆記筆記
- Segment Tree(線段樹)
- 線段樹入門
- 李超線段樹
- 線段樹進階
- 藍橋杯 演算法訓練 操作格子 (線段樹)演算法
- 洛谷題單指南-線段樹-P3373 【模板】線段樹 2
- 線段樹擴充套件套件
- 第二課——線段樹
- 線段樹簡單思路
- 深入理解線段樹
- 線段樹(毒瘤)總結
- POJ 3667 Hotel 線段樹
- poj 2667 hotel 線段樹
- 線段樹(超詳解)
- 線段樹 transformation——hdu 4578ORM
- 懶標記線段樹
- 可持久化線段樹持久化
- 線段樹模板總結
- 線段樹 - 多組圖帶你從頭到尾徹底理解線段樹
- 資料結構之樹( 線段樹,字典樹)資料結構
- hdu 1698 線段樹 一段更新染色
- 線段樹也能是 Trie 樹 題解
- 線段樹從零開始