D. Array Restoration(思维+区间极值(线段树or树状数组))

题目链接、

题意:

给一个n个初始数字的序列。

问能不能通过一系列操作将0转化后,变成合法的串。一系列操作就是第i次可以将某段闭区间都变成i。一共要(必须)操作q次

解:

1,两个相同的数字之间的数不能小于这个数(这里查询用树状数组or线段树or st表都可以)

2,必须要有q(没有的话0也可以)

3,0的位置填它左右位置的数即可,如果没有q的话必须将一个0填成q

 

代码、--线段树

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
int n,q,a[maxn],pre[maxn],vis[maxn];
struct node{
    int l,r,val;
}tree[maxn<<2];
void push_up(int x){
    tree[x].val = min(tree[x<<1].val,tree[x<<1|1].val);
}
void build(int x,int l,int r){
    tree[x].l = l,tree[x].r = r;
    if(l == r)
        tree[x].val = a[l];
    else{
        int mid = (l+r)>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        push_up(x);
    }
}
int query(int x,int l,int r){
    int L = tree[x].l,R = tree[x].r;
    if(l<=L && R<=r)
        return tree[x].val;
    else{
        int mid = (L+R)>>1;
        int ans = q+1;
        if(l <= mid)ans = min(ans,query(x<<1,l,r));
        if(r > mid )ans = min(ans,query(x<<1|1,l,r));
        return ans;
    }
}
int main(){
    int Mx = 0,cnt = 0;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        Mx = max(Mx,a[i]);
        if(a[i] == 0)++cnt;
    }
    if(Mx != q && !cnt)return 0*puts("NO");/// *2
    if(cnt == n)for(int i=1;i<=n;i++)a[i]=q;
    if(Mx != q && cnt)for(int i=1;i<=n;i++)if(a[i] == 0){a[i] = q;break;}/// *3
    for(int i = 1; i <= n; i++)if(a[i] == 0) a[i] = a[i-1];/// *3
    for(int i = n; i >= 1; i--)if(a[i] == 0) a[i] = a[i+1];
    build(1,1,n);
    //printf("%d \n",query(1,1,n));
    for(int i=n;i;i--){
        pre[i] = vis[a[i]];
        vis[a[i]] = i;
    }
    for(int i=1;i<=n;i++){
        if(pre[i]){
            if(query(1,i,pre[i])<a[i])/// *1
                return 0*puts("NO");
        }
    }
    puts("YES");
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
    return 0;
}

代码、zkw线段树

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
int n,q,a[maxn],pre[maxn],vis[maxn];
int M,tree[maxn<<2];
void push_up(int x){tree[x] = min(tree[x<<1],tree[x<<1|1]);}
void build(int n){
    for(M=1;M<n;M<<=1);
    for(int i=M+1;i<=M+n;i++)tree[i] = a[i-M];
    for(int i=M;i;i--)push_up(i);
}
int query(int l,int r,int ans = 0x3f3f3f3f){
    for(l = M+l-1,r = M+r+1;l^r^1;l>>=1,r>>=1){/// [l,r] --> (l-1,r+1)
        if(l&1^1) ans = min(ans,tree[l^1]);/// l%2 == 0, tree[l+1]
        if(r&1)   ans = min(ans,tree[r^1]);/// r%2 == 1, tree[r-1]
    }
    return ans;
}
int main(){
    int Mx = 0,cnt = 0;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        Mx = max(Mx,a[i]);
        if(a[i] == 0)++cnt;
    }
    if(Mx != q && !cnt)return 0*puts("NO");/// *2
    if(cnt == n)for(int i=1;i<=n;i++)a[i]=q;
    if(Mx != q && cnt)for(int i=1;i<=n;i++)if(a[i] == 0){a[i] = q;break;}/// *3
    for(int i = 1; i <= n; i++)if(a[i] == 0) a[i] = a[i-1];/// *3
    for(int i = n; i >= 1; i--)if(a[i] == 0) a[i] = a[i+1];
    build(n);
    for(int i=n;i;i--){
        pre[i] = vis[a[i]];
        vis[a[i]] = i;
    }
    for(int i=1;i<=n;i++){
        if(pre[i]){
            if(query(i,pre[i])<a[i])/// *1
                return 0*puts("NO");
        }
    }
    puts("YES");
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
    return 0;
}

 

 

st表

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+7;
int n,q,a[maxn],pre[maxn],vis[maxn];
int st[maxn][50],Log[maxn];
void init(){
    Log[0] = -1;
    for(int i=1;i<=n;i++)
        Log[i] = (i&(i-1))==0?Log[i-1]+1:Log[i-1],st[i][0] = a[i];
    for(int j=1;j<=Log[n];j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j] = min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int query(int l,int r){
    int k = Log[r-l+1];
    return min(st[l][k],st[r-(1<<k)+1][k]);
}
int main(){
    int Mx = 0,cnt = 0;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        Mx = max(Mx,a[i]);
        if(a[i] == 0)++cnt;
    }
    if(Mx != q && !cnt)return 0*puts("NO");
    if(cnt == n)for(int i=1;i<=n;i++)a[i]=q;
    if(Mx != q && cnt)for(int i=1;i<=n;i++)if(a[i] == 0){a[i] = q;break;}
    for(int i = 1; i <= n; i++)if(a[i] == 0) a[i] = a[i-1];
    for(int i = n; i >= 1; i--)if(a[i] == 0) a[i] = a[i+1];
    init();
    for(int i=n;i;i--){
        pre[i] = vis[a[i]];
        vis[a[i]] = i;
    }
    for(int i=1;i<=n;i++){
        if(pre[i]){
            if(query(i,pre[i])<a[i])
                return 0*puts("NO");
        }
    }
    puts("YES");
    for(int i=1;i<=n;i++)printf("%d ",a[i]);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值