题目链接
题目思路
就是用线段树维护答案,可以把每个点当作次大值和次小值的贡献,然后往左往右找最大值和最小值,如果要更新就更新这个点距离k的元素。注意不要写查询函数,因为是查询总区间,直接tree[1]就行了。有点口胡,实在不好表示
代码
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef unsigned long long ull;
typedef pair<int,int > pii;
const int maxn=1e5+5,inf=0x3f3f3f3f;
const double eps=1e-10;
int t,k,n,a[maxn],tree1[maxn<<2],tree2[maxn<<2],b1[maxn],b2[maxn];
void build(int node,int l,int r){
if(l==r){
tree1[node]=b1[l];
tree2[node]=b2[l];
return ;
}
int mid=(l+r)>>1;
build(node<<1,l,mid);
build(node<<1|1,mid+1,r);
tree1[node]=max(tree1[node<<1],tree1[node<<1|1]);
tree2[node]=min(tree2[node<<1],tree2[node<<1|1]);
}
void update(int node,int pos,int ma,int mi,int l,int r){
if(l==r){
tree1[node]=ma;
tree2[node]=mi;
return ;
}
int mid=(l+r)>>1;
if(mid>=pos) update(node<<1,pos,ma,mi,l,mid);
else update(node<<1|1,pos,ma,mi,mid+1,r);
tree1[node]=max(tree1[node<<1],tree1[node<<1|1]);
tree2[node]=min(tree2[node<<1],tree2[node<<1|1]);
}
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
scanf("%d%d",&t,&k);
for(int i=1;i<=n;i++){
int ma=-inf,mi=inf;
for(int j=1;j<=k;j++){
ma=max(ma,a[(i+j-1)%n+1]);
mi=min(mi,a[(i+j-1)%n+1]);
ma=max(ma,a[(i-j-1+n)%n+1]);
mi=min(mi,a[(i-j-1+n)%n+1]);
}
b1[i]=a[i]+ma,b2[i]=a[i]+mi;
}
build(1,1,n);
for(int i=1,opt,x,y;i<=t;i++){
scanf("%d",&opt);
if(opt==1){
scanf("%d%d",&x,&y);
a[x]=y;
vector<int> vec;
vec.clear();
vec.push_back(x);
for(int j=1;j<=k;j++){
vec.push_back((x+j-1)%n+1);
vec.push_back((x-j-1+n)%n+1);
}
for(int j=0;j<(int)vec.size();j++){
int pos=vec[j],ma=-inf,mi=inf;
for(int c=1;c<=k;c++){
ma=max(ma,a[(pos+c-1)%n+1]);
mi=min(mi,a[(pos+c-1)%n+1]);
ma=max(ma,a[(pos-c-1+n)%n+1]);
mi=min(mi,a[(pos-c-1+n)%n+1]);
}
update(1,pos,a[pos]+ma,a[pos]+mi,1,n);
}
}else{
printf("%d %d\n",tree1[1],tree2[1]);
}
}
return 0;
}