题目链接、
题意:
给一个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;
}