Codeforces Round #698 (Div. 1) B. Nezzar and Binary String(思维+线段树)

传送门

题意:

给出两个 01 01 01字符串 s , t s,t s,t ,对字符串 s s s q q q次查询,查询用区间 [ l , r ] [l,r] [l,r]表示,每次查询区间内的字符是否一致,若不一致,输出 N O NO NO ,反之则可以在查询完后修改这个区间内少于一半的字符,最后问能否使得字符串 s s s变为 t t t

题解:

假如我们根据题目操作一步一步来,就会发现我们很难知道要修改哪些字符。因此正难则反,考虑倒推,看字符串 t t t能否变成字符串 s s s 。当我们倒着做,会发现修改操作先于查询操作,而查询操作要求区间内字符一样,也就意味着修改操作其实是固定了,即我们只能利用修改操作将此区间变为一致,而不能用于其他。

考虑怎么修改:线段树。利用线段树维护区间 01 01 01的个数。

1. 1. 1. 当区间 1 1 1的数量多于 0 0 0的数量时,我们就要把区间变为全 1 1 1

2. 2. 2.当区间 0 0 0的数量多于 1 1 1的数量时,我们就要把区间变为全 0 0 0

3.数量相等时,无法修改

最后判断 t t t是否等于 s s s即可

代码:

#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=2e5+5;
const int inf=0x3f3f3f3f;
char s1[MAXN],s2[MAXN];
int x[MAXN],y[MAXN];
struct node
{
    int l,r;
    int sum;
    int lazy;
}node[MAXN<<2];
void push_up(int num){
    node[num].sum=node[num<<1].sum+node[num<<1|1].sum;
}
void push_down(int num){
    if(node[num].lazy!=-1){
        node[num<<1].lazy=node[num<<1|1].lazy=node[num].lazy;
        node[num<<1].sum=(node[num<<1].r-node[num<<1].l+1)*node[num].lazy;
        node[num<<1|1].sum=(node[num<<1|1].r-node[num<<1|1].l+1)*node[num].lazy;
        node[num].lazy=-1;
    }
}
void build(int l,int r,int num){
    node[num].l=l;
    node[num].r=r;
    node[num].lazy=-1;
    if(l==r){
        node[num].sum=s2[l]-'0';
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
    push_up(num);
}
int query(int l,int r,int num){
    if(node[num].l>=l&&node[num].r<=r){
        return node[num].sum;
    }
    int sum=0;
    push_down(num);
    int mid=(node[num].l+node[num].r)>>1;
    if(l<=mid){
        sum+=query(l,r,num<<1);
    }
    if(r>mid){
        sum+=query(l,r,num<<1|1);
    }
    return sum;
}
void updata(int l,int r,int val,int num){
    if(node[num].l>=l&&node[num].r<=r){
        node[num].sum=(node[num].r-node[num].l+1)*val;
        node[num].lazy=val;
        return;
    }
    push_down(num);
    int mid=(node[num].l+node[num].r)>>1;
    if(l<=mid){
        updata(l,r,val,num<<1);
    }
    if(r>mid){
        updata(l,r,val,num<<1|1);
    }
    push_up(num);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,q;
        scanf("%d%d",&n,&q);
        scanf("%s",s1+1);
        scanf("%s",s2+1);
        for(int i=1;i<=q;i++){
            scanf("%d%d",&x[i],&y[i]);
        }
        build(1,n,1);
        int flag=0;
        for(int i=q;i>=1;i--){
            int res1=query(x[i],y[i],1);
            int res2=y[i]-x[i]+1-res1;
            if(res1<res2) updata(x[i],y[i],0,1);
            else if(res2<res1) updata(x[i],y[i],1,1);
            else {flag=1;break;}
        }
        if(flag) printf("NO\n");
        else{
            
            for(int i=1;i<=n;i++){
                int id=s1[i]-'0';
                if(id!=query(i,i,1)){
                    flag=1;
                    break;
                }
            }
            if(flag) printf("NO\n");
            else printf("YES\n");
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值