【CF1023D】Array Restoration

文章讲述了在洛谷竞赛中如何通过给定的区间操作序列,判断是否能将一个全零初始的数列转换成指定的数列。使用ST结构(SegmentTree)进行区间查询,分析了操作限制和条件,涉及动态规划思想。

Array Restoration - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)icon-default.png?t=N7T8https://www.luogu.com.cn/problem/CF1023D

题意翻译

给你一个长度为 $n$ 的数列,初始全部为 $0$ ,你可以任意(任选区间)进行 $q$ 次操作,第 $i$ 次操作使 $[l_i,r_i]$ 内的数全部变为 $i$ ,你必须进行全部 $q$ 次操作,且每个操作区间都不能为空,所有操作区间的并必须为 $[1,n]$。

现在给你一个数列,其中 $0$ 代表这个位置可以是任何数,问你能否通过上述的 $q$ 次操作得到这个数列。

输入为第一行 $n\ q$ 第二行 $n$ 个整数 $a_i$

能得到则输出"YES"以及任意一种方案(最后得到的数列,需要把所有 $0$ 替换成其它数),不能则输出"NO"。

数据范围见英文题面

细节特别多,调了2个小时(悲伤的故事) 

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5+10;
int a[maxn];
int l[maxn],r[maxn],b[maxn];
struct ST{
	int lg[maxn],st_min[maxn][19],st_max[maxn][19];
	void init(int a[],int n){
		lg[0] = -1;
		for(int i = 1;i <= n;i++){
			lg[i] = lg[i/2]+1;
			st_min[i][0] = st_max[i][0] = a[i];
			if(a[i] == INF){
			    st_max[i][0] = -INF;
			   // cout<<st_max[i][0]<<endl;
		    }
		}
		for(int j = 1;j <= lg[n];j++){
			for(int i = 1;i <= n;i++){
				if(i+(1<<j-1) > n)continue;
			    st_min[i][j] = min(st_min[i][j-1],st_min[i+(1<<j-1)][j-1]);	
				st_max[i][j] = max(st_max[i][j-1],st_max[i+(1<<j-1)][j-1]);		
			}
		}
	}
	int qmin(int l,int r){
		int k = lg[r-l+1];
		return min(st_min[l][k],st_min[r-(1<<k)+1][k]);
	}
	int qmax(int l,int r){
		int k = lg[r-l+1];
		return max(st_max[l][k],st_max[r-(1<<k)+1][k]);
	}
}A1,A2,B1,B2;
int cnt[maxn],l0;
int main() {
    int n,q;
    cin >> n>>q;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        if(a[i] == 0)l0 = i;
        cnt[a[i]]++;
    }
    if(cnt[q] == 0){
		if(cnt[0] == 0){
			cout<<"NO";
			return 0;
		} 
		else a[l0] = q;
	}
    bool pd = (a[1] == 0);
    for(int i = 2;i <= n;i++){
    	if(a[i] == 0){
    		a[i] = a[i-1];
		}
		else{
			pd = 0;
		}
	}
	for(int i = n-1;i >= 1;i--){
    	if(a[i] == 0){
    		a[i] = a[i+1];
		}
	}
	if(pd == 1){
		cout<<"YES"<<endl;
		for(int i = 1;i <= n;i++){
			cout<<q<<" ";
		}
		return 0;
	}
	for(int i = 1;i <= n;i++){
        if(l[a[i]] == 0)l[a[i]] = i;
        r[a[i]] = i;
	}
    A1.init(a,n);
    for (int i=1;i<=q;i++){
    	if(l[i] == 0)continue;
        if(A1.qmin(l[i],r[i]) < i){
        	cout<<"NO"<<endl;
        	return 0;
		}
    }
    cout<<"YES"<<endl;
    for(int i = 1;i <= n;i++){
    	cout<<a[i]<<" ";
	}
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值