线段树+cf1478E
线段树+cf1478E
(先贴代码,细节以后补充QAQ)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int maxn = 2e5 + 10;//电脑竟然关机重启了,登录一小时,气死我了
struct str {
int l,r,sum,lazy;
};
struct fx{
int x,y;
};
str tree[maxn<<2];
fx b[maxn];
int a[maxn],cs[maxn];
void pushup(int node){//线段树子节点与父亲节点关系的维护
tree[node].sum=tree[node<<1|1].sum+tree[node<<1].sum;
}
void build(int node ,int start,int end){//建立线段树
tree[node]={start,end,0,-1};
if(start==end){
tree[node].sum=a[end];//边界条件,也就是到了叶子节点
return;
}
int mid=(start+end)>>1;
build(node<<1,start,mid);//左边的儿子的建立,用的是完全二叉树的性质
build(node<<1|1,mid+1,end); //右边的儿子的建立。
pushup(node);
}
void pushdown(int node){
if(tree[node].lazy!=-1){
tree[node<<1].lazy=tree[node<<1|1].lazy=tree[node].lazy;//继承标记
tree[node<<1|1].sum=(tree[node<<1|1].r-tree[node<<1|1].l+1)*tree[node].lazy,tree[node<<1].sum=(tree[node<<1].r-tree[node<<1].l+1)*tree[node].lazy;//传递数值,因为我们这里用的只是改变数值,所以不用去用加法,直接等于就行了
tree[node].lazy=-1;//父节点的标记去掉
}
}
void update(int node,int l, int r,int val)//start,end代表的是要用的区间(现在在查询的区间),l,r代表的是要改的区间,val是要修改的数值
{
if(l<=tree[node].l&& tree[node].r<=r){//如果改变的区间在我们查询的区间之内就直接改变
tree[node].lazy=val;
tree[node].sum=(tree[node].r-tree[node].l+1)*tree[node].lazy;
// cout<<tree[node].sum<<"\n";
return;
}//如果不是正好在区间内,或者是有一半在里面啥的
pushdown(node);
// cout<<"?\n";
int m=(tree[node].r+tree[node].l)>>1;
if(l<=m) update(node<<1,l,r,val);//如果要查询的区间在mid左边有交集,那么就去左边继续找
if(r>m) update(node<<1|1,l,r,val);//如果要查询的区间在mid右边。
pushup(node);
}
int query(int node,int l,int r){//查询函数
// cout<<start<<" "<<end<<"\n"<<l<<" "<<r<<"?\n";
if(l<=tree[node].l&& tree[node].r<=r){//如果查询的区间在我们的范围内
return tree[node].sum;//直接返回这个节点的值
}
pushdown(node);//如果不是的话,先使将这个节点的标记传递,并且改变数值来维护线段树的区间修改。
int m=(tree[node].r+tree[node].l)>>1;
int res=0;
if(r>m) res+=query(node<<1|1,l,r);//查右边边
if(l<=m) res+=query(node<<1,l,r); //左边
return res;
}
signed main(){
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
//cout<<i<<"\n";
scanf("%1d",&cs[i]);//还可以这样用啊!又看博客学到了
}
for(int i=1;i<=n;i++){
//cout<<i<<"\n";
scanf("%1d",&a[i]);
}
for(int i=1;i<=k;i++){
cin>>b[i].x>>b[i].y;
}
build(1,1,n);
bool flag=1;
for(int i=k;i>=1;i--){//倒过来操作 ,看题解说正向操作,区间不同,但是反向复原的话,就能保证区间染色一致
int l=b[i].x,r=b[i].y;
int num=(r-l)>>1;//区间有多少数字,方便查询
int one=query(1,l,r);
int zero=r-l+1-one;//剩下的肯定是零的数量
if(zero<=num){//零的数量没有超过一般
update(1,l,r,1);
// cout<<"?";
}
else if(one<=num){
update(1,l,r,0);
}
else{
flag=0;//数量是对半分,那就不能改,出事了
break;
}
// for(int i=1;i<=n<<2;i++) cout<<tree[i].sum;
// cout<<"\n";
}
for(int i=1;i<=n;i++){
int z=query(1,i,i);
if(cs[i]!=z){
flag=0;
break;
}
}
if(flag) cout<<"YES\n";
else cout<<"NO\n";
}
}

浙公网安备 33010602011771号