【题解】CF1847D Professor Higashikata

题面传送门

解决思路

首先我们考虑,优先把原字符串 s 中哪些位置变 1 会使得拼接后字符串 t 的字典序尽可能大。我们把每个位置的这一信息称为“优先级”。根据题目意思可以得出,将 m 个区间依次拼接,一个位置第一次出现越靠前,它的优先级越高。

然后考虑如何求出每个位置的优先级。这里讲一种区间覆盖的方法。从最后一个区间开始做区间覆盖。对于第 mi+1(1im) 个区间,我们将这个区间的值覆盖为 i。所有区间覆盖完成后,对全部位置进行排序:第一关键字为覆盖上去的值,从大到小(最后被覆盖的说明区间靠前,优先级高);第二关键字为原先的位置,从小到大(同一区间内位置靠前的优先)。这样我们就得出了每个位置的优先级。

再考虑求出优先级后如何计算每次询问的答案。我们假设当前原字符串 有用的 1 的个数为 cnt,那么要使得拼接得到的字符串 t 的字典序最大,应该让原字符串中优先级前 cnt 个位置全部变成 1。设原字符串中优先级前 cnt 个位置当前有 tot1。那么答案显而易见,就是 cnttot

注意上一段的粗体字:什么是有用的 1?考虑一种情况,那就是原字符串 s 中,有一些位置根本没有出现在拼接后字符串 t 中。这些位置上是 01 是无所谓的。所以如果计算全部 1 的个数作为 cnt,就可能导致一些无关的位置被变成 1,从而使答案偏大。所以 cnt 应该是 min(总共 1 的个数,在 t 串中出现过的位置数)。(没有考虑这一点会导致 Wa on 13

具体实现中,区间覆盖和维护 1 的个数我选用的都是线段树,所以看着比较长,其实是不难写的。

AC Code

//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
using namespace std;
struct SGT{
    struct node{
        int l,r,sum,tag;
    }tr[800005]; 
    void build(int i,int l,int r){
        tr[i].l=l,tr[i].r=r,tr[i].tag=0;
        if(l==r) return ;
        int mid=(l+r)>>1;
        build(ls(i),l,mid),build(rs(i),mid+1,r);
        tr[i].sum=tr[ls(i)].sum+tr[rs(i)].sum;
    }
    void pushdown(int i){
        if(tr[i].tag){
            tr[ls(i)].tag=tr[i].tag;
            tr[rs(i)].tag=tr[i].tag;
            tr[ls(i)].sum=(tr[ls(i)].r-tr[ls(i)].l+1)*tr[i].tag;
            tr[rs(i)].sum=(tr[rs(i)].r-tr[rs(i)].l+1)*tr[i].tag;
            tr[i].tag=0;
        }
    }
    void turn(int i,int l,int r,int k){
        if(tr[i].l>=l&&tr[i].r<=r){
            tr[i].tag=k,tr[i].sum=(tr[i].r-tr[i].l+1)*k;
            return ;
        }
        pushdown(i);
        int mid=(tr[i].l+tr[i].r)>>1;
        if(l<=mid) turn(ls(i),l,r,k);
        if(mid<r) turn(rs(i),l,r,k);
        tr[i].sum=tr[ls(i)].sum+tr[rs(i)].sum; 
    }
    int query(int i,int l,int r){
        if(tr[i].l>=l&&tr[i].r<=r) return tr[i].sum;
        pushdown(i);
        int mid=(tr[i].l+tr[i].r)>>1,ans=0;
        if(l<=mid) ans+=query(ls(i),l,r);
        if(mid<r) ans+=query(rs(i),l,r);
        return ans;
    }
}sgt;

struct SGT2{
    struct node{
        int l,r,sum,tag;
    }tr[800005]; 
    void build(int i,int l,int r){
        tr[i].l=l,tr[i].r=r,tr[i].sum=tr[i].tag=0;
        if(l==r){
        	tr[i].sum=0;
        	return ;
		}
        int mid=(l+r)>>1;
        build(ls(i),l,mid),build(rs(i),mid+1,r);
        tr[i].sum=tr[ls(i)].sum+tr[rs(i)].sum;
    }
    void pushdown(int i){
        if(tr[i].tag){
            tr[ls(i)].tag+=tr[i].tag;
            tr[rs(i)].tag+=tr[i].tag;
            tr[ls(i)].sum+=(tr[ls(i)].r-tr[ls(i)].l+1)*tr[i].tag;
            tr[rs(i)].sum+=(tr[rs(i)].r-tr[rs(i)].l+1)*tr[i].tag;
            tr[i].tag=0;
        }
    }
    void add(int i,int l,int r,int k){
        if(tr[i].l>=l&&tr[i].r<=r){
            tr[i].tag+=k,tr[i].sum+=(tr[i].r-tr[i].l+1)*k;
            return ;
        }
        pushdown(i);
        int mid=(tr[i].l+tr[i].r)>>1;
        if(l<=mid) add(ls(i),l,r,k);
        if(mid<r) add(rs(i),l,r,k);
        tr[i].sum=tr[ls(i)].sum+tr[rs(i)].sum; 
    }
    int query(int i,int l,int r){
        if(tr[i].l>=l&&tr[i].r<=r) return tr[i].sum;
        pushdown(i);
        int mid=(tr[i].l+tr[i].r)>>1,ans=0;
        if(l<=mid) ans+=query(ls(i),l,r);
        if(mid<r) ans+=query(rs(i),l,r);
        return ans;
    }
}sgt2;

struct node{
	int l,r;
}a[200005];
struct dot{
	int id,rk;
}b[200005];
bool cmp(dot a,dot b){
	if(a.rk==b.rk) return a.id<b.id;
	return a.rk>b.rk;
}
int T,n,m,q,t;
string s;
int yxj[200005];
void solve(){
	cin>>n>>m>>q>>s;
	s=" "+s;
	for(int i=1;i<=m;i++) cin>>a[i].l>>a[i].r;
	int tmp=1;
	sgt.build(1,1,n);
	for(int i=m;i>=1;i--) sgt.turn(1,a[i].l,a[i].r,tmp++);
	for(int i=1;i<=n;i++) b[i]={i,sgt.query(1,i,i)};
	sort(b+1,b+n+1,cmp);
	int mx=n;
	for(int i=1;i<=n;i++){
		yxj[b[i].id]=i;
		if(b[i].rk==0) mx=min(mx,i-1);
	}
	int c1=0;
	sgt2.build(1,1,n);
	for(int i=1;i<=n;i++){
		if(s[i]=='1') c1++,sgt2.add(1,yxj[i],yxj[i],1);
	}
	while(q--){
		cin>>t;
		if(s[t]=='0'){
			s[t]='1';c1++;
			sgt2.add(1,yxj[t],yxj[t],1);
		}
		else{
			s[t]='0';c1--;
			sgt2.add(1,yxj[t],yxj[t],-1);
		}
		cout<<min(c1,mx)-sgt2.query(1,1,min(c1,mx))<<endl;
	}
}
signed main(){
	IOS;TIE;
	T=1;
	while(T--) solve();
	return 0;
}
posted @   Binary_Lee  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
Title
点击右上角即可分享
微信分享提示