小A的題 線段樹區間賦值
阿新 • • 發佈:2020-12-16
小A的題
描述
由於小 A 實在是太菜了,因此他現在需要你的幫助: 現在小 A 手上有一個凌亂的 01 串,他想通過若干次對於這個 01 串的區域性排序將它變成一個有趣的 01 序列。 現在有兩種操作:
輸入格式
l r 00 表示把區間 [l,r][給升序排序
l r 11 表示把區間 [l,r]給降序排序
然後小 A 這個菜雞想知道在 m次操作之後序列長啥樣。
輸出格式
第一行一個 01 串 S。 第二行一個整數 m。 接下來 m 行每行三個整數 l,r,x,保證\(l \le r \ \ \ and \ \ x=0\) 中的一個。
m 次操作之後的 01 串
資料範圍
\(|S| \le 1000000,m \le 500000∣S∣≤1000000,m≤500000\)
輸出時每行末尾的多餘空格,不影響答案正確性
樣例輸入
11001
1
2 4 0
樣例輸出
10011
因為區間只有01,降序排序之後左邊全是1,右邊全是0,所以,維護區間1的個數,0的個數=區間長度-1的個數。
#include<bits/stdc++.h> using namespace std; const int inf=0x3f3f3f3f,mod=1e9+7,MAXN=1e6+4; #define lson (i<<1) #define rson (i<<1|1) #define mid ((l+r)>>1) int one[MAXN<<2],n,t;//one:1的個數 bool lazy[MAXN<<2]; char ans[MAXN]; void down(int i,int l,int r){ one[lson]=one[i]?(mid-l+1):0; one[rson]=one[i]?r-mid:0; lazy[lson]=lazy[rson]=1; lazy[i]=0; } int sum(int x,int y,int i=1,int l=1,int r=n){ if(x<=l&&r<=y)return one[i]; int res=0; if(lazy[i])down(i,l,r); if(x<=mid)res+=sum(x,y,lson,l,mid); if(y>mid)res+=sum(x,y,rson,mid+1,r); return res; } void up(int i,int l,int r){ one[i]=one[lson]+one[rson]; } void change(int x,int y,int val,int i=1,int l=1,int r=n){ if(x>y)return; if(x<=l&&r<=y){ lazy[i]=1; one[i]=val?r-l+1:0; return; } if(lazy[i])down(i,l,r); if(x<=mid)change(x,y,val,lson,l,mid); if(y>mid)change(x,y,val,rson,mid+1,r); up(i,l,r); } void build(int i=1,int l=1,int r=n){ if(l==r){ if(ans[l]=='1')one[i]=1; return; } build(lson,l,mid); build(rson,mid+1,r); up(i,l,r); } void print(int i=1,int l=1,int r=n){ if(l==r){ putchar(one[i]+48); return; } if(lazy[i])down(i,l,r); print(lson,l,mid); print(rson,mid+1,r); } int main() { char ch=getchar(); while(ch!='\n'){ ans[++n]=ch; ch=getchar(); } build(); scanf("%d",&t); int x,y,op,yi,m; while(t--){ scanf("%d%d%d",&x,&y,&op); if(x>y)continue; yi=sum(x,y); if(!yi||y-x+1==yi)continue; if(op==1){ m=yi+x-1; change(x,m,1); change(m+1,y,0); }else if(op==0){ m=y-yi; change(x,m,0); change(m+1,y,1); } } print(); return 0; }