题一
题二
题三
分析(题一)
一道模拟题
但模拟也是有很多坑的……
写出一道题后,一定要自己试很多很多很多组不同的数据
比如这道题,几乎我试的每一组数据都找出了我程序的bug,好险~
分析(题二)
好题!!!!
应该是和松鼠聚会这道题本质一样的
首先我们需要推导出任意两个点(x,y) (a,b)之间能够到达彼此所需要走的最短步数,由于可以斜着走,那么我们肯定会优先走对角线,然后再直线走到目标位置,对角线的步数:,直线的话再推一下
就可以得到答案,这不就是切比雪夫距离(⊙_⊙)?
自然想到将其转为曼哈顿距离
常用套路一用,O(∩_∩)O哈哈~(妙哉,虽然我没想出来)
分析(题三)
我的暴力……居然爆0
究其原,还是思维有漏洞,大大的bug!!!
想贴一下自己的代码,然后好好吐槽一下自己
改了下面两个地方后,就多了33分,感谢wcr大佬!!!Orz
再次感谢cyk大佬!!!让我又一跃成了50分
#include<bits/stdc++.h>
#define in read()
#define N 500009
#define lc (k<<1)
#define rc (k<<1)|1
#define inf 1000000009
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
int n,a[N],minn[4*N],m,lzy[4*N],b[N];
void build(int k,int l,int r){
lzy[k]=inf;
if(l==r){
minn[k]=a[l];
return;
}
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
minn[k]=min(minn[lc],minn[rc]);
}
void pushdown(int k){
if(lzy[k]!=inf){
if(minn[lc]<lzy[k]) {minn[lc]=lzy[k];lzy[lc]=lzy[k];}
if(minn[rc]<lzy[k]){minn[rc]=lzy[k];lzy[rc]=lzy[k];}
lzy[k]=inf;
}
}
void modify(int k,int l,int r,int x,int y,int z){
if(x<=l&&r<=y){
//lzy[k]=z;minn[k]=z;//你看pushdown我都知道要取max……,但这个地方居然没有取???
lzy[k]=max(lzy[k],z);minn[k]=max(minn[k],z);
return;
}
pushdown(k);
int mid=l+r>>1;
if(x<=mid) modify(lc,l,mid,x,y,z);
if(y>mid) modify(rc,mid+1,r,x,y,z);
minn[k]=min(minn[lc],minn[rc]);
}
int query(int k,int l,int r,int x,int y){
if(x<=l&&r<=y){
return minn[k];
}
pushdown(k);
int mid=l+r>>1,res=inf;
if(x<=mid) res=min(res,query(lc,l,mid,x,y));
if(y>mid) res=min(res,query(rc,mid+1,r,x,y));
return res;
}
int main(){
n=in;
int i,j,k;
for(i=1;i<=n;++i) a[i]=in;
if(n<=3000){
m=in;int op,l,r,x;
while(m--){
op=in;l=in;r=in;x=in;
if(op==1){
for(int i=l;i<=r;++i)
if(a[i]<x) a[i]=x;
}
else{
k=in;
memcpy(b,a,sizeof(a));
sort(b+l,b+r+1);
int pos=lower_bound(b+l,b+r+1,x)-b;
pos--;while(b[pos]==x) pos--;
if(pos>=k+l-1){//////////相对位置的关系
for(int i=l;i<=l+k-1;++i) printf("%d ",b[i]);////////怎么可以从1开始!!!!
printf("\n");
}
else printf("-1\n");
}
}
}
else{
build(1,1,n);
m=in;
int op,l,r,x;
while(m--){
op=in;l=in;r=in;x=in;
if(op==1){
modify(1,1,n,l,r,x);
}
else{
k=in;
if(k==1){
int mn=query(1,1,n,l,r);
if(mn>=x) printf("-1\n");////////如果只判等的话,那要是这个区间的最小值大于x呢?还不是不行
else printf("%d\n",mn);
}
}
}
}
return 0;
}
现在来讲一下正解吧
修改比较简单,就是线段树的区间修改
因为现在我们将区间[l,r]中所有小于 x 的数都赋为 x ,那么 x 肯定就是此时的区间最小值
维护一下就好了
只是需要注意,若这个区间的最小值本就大于 x ,那我们是修改不了的
所以取个max
然后对于查询
我们观察一下数据范围,可以发现 k 总和都不超过5*10^6,是个突破口
所以我们查询区间[L,R]中比 X小的最小的 K 个数,就可以变成求 K 次区间最小值,每求完一次就暂时将这个位置的值赋为INF,避免其对下次求最小值有影响,然后在这次操作完了之后将所有的“最小值”还原其本来的值
操作细节:由于我们需要还原,所以我们得记录下每个最小值的位置。那就用一个二元组(pair<int,int>)来存储线段树中每个节点的信息。first -- > 值,second-->位置
代码走一波(稍微需要卡一下常)
#include<bits/stdc++.h>
#define in read()
#define N 500009
#define lc (k<<1)
#define rc (k<<1)|1
#define inf 1000000009
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
int n,a[N],m,lzy[4*N];
pair<int,int> minn[4*N];
inline void build(int k,int l,int r){
lzy[k]=0;
if(l==r){
minn[k]=make_pair(a[l],l);
return;
}
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
minn[k]=min(minn[lc],minn[rc]);
}
inline void pushdown(int k){
if(minn[lc].first<lzy[k]) {minn[lc].first=lzy[k];lzy[lc]=lzy[k];}
if(minn[rc].first<lzy[k]){minn[rc].first=lzy[k];lzy[rc]=lzy[k];}
lzy[k]=0;
}
inline void modify(int k,int l,int r,int x,int y,int z){
if(x<=l&&r<=y){
lzy[k]=max(z,lzy[k]);
minn[k].first=max(z,minn[k].first);
return;
}
if(lzy[k]) pushdown(k);
int mid=l+r>>1;
if(x<=mid) modify(lc,l,mid,x,y,z);
if(y>mid) modify(rc,mid+1,r,x,y,z);
minn[k]=min(minn[lc],minn[rc]);
}
pair<int,int> query(int k,int l,int r,int x,int y){
if(x<=l&&r<=y) return minn[k];
if(lzy[k]) pushdown(k);
int mid=l+r>>1;
pair<int,int> res;res.first=inf;
if(x<=mid) res=min(res,query(lc,l,mid,x,y));
if(y>mid) res=min(res,query(rc,mid+1,r,x,y));
return res;
}
inline void insert(int k,int l,int r,int p,int x){
if(l==r){
minn[k].first=x;
return ;
}
if(lzy[k]) pushdown(k);
int mid=l+r>>1;
if(p<=mid) insert(lc,l,mid,p,x);
else insert(rc,mid+1,r,p,x);
minn[k]=min(minn[lc],minn[rc]);
}
int main(){
n=in;
int i,j,k;
for(i=1;i<=n;++i) a[i]=in;
build(1,1,n);
m=in;
int op,l,r,x;
while(m--){
op=in;l=in;r=in;x=in;
if(op==1){
modify(1,1,n,l,r,x);
}
else{
k=in;int flag=0;
vector<pair<int,int> > V;
for(i=1;i<=k;++i){
pair<int,int> mn=query(1,1,n,l,r);
if(mn.first>=x) {flag=1;break;}
V.push_back(mn);
insert(1,1,n,mn.second,inf);
}
if(!flag) for(i=0;i<V.size();++i) printf("%d ",V[i].first);
else printf("-1");
printf("\n");
for(i=0;i<V.size();++i) insert(1,1,n,V[i].second,V[i].first);
}
}
return 0;
}