小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!='
'){
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;
}