题意(题意转自网络):
三种操作0 x y 把x位置的值改成y
1 x y 交换x与y位置的值
2 x y 统计[x,y]中连续k个值的最大值
我们把1-k的和值作为b[1],2-(k+1)的和值作为b[2],以此类推
那么可以建立一棵[1,n-k+1]的线段树
求连续k个和的最大值,退化为求某个区间的最值问题
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define havemid int m=(l+r)>>1
#define left (rt<<1)
#define right (rt<<1|1)
const int maxn=200005;
int fa[maxn];
int t[maxn];
int maxval[maxn<<2];
int add[maxn<<2];
void pushup(int rt){
maxval[rt]=max(maxval[left],maxval[right]);
}
void pushdown(int rt){
if(add[rt]!=0){
add[left]+=add[rt];
add[right]+=add[rt];
maxval[left]+=add[rt];
maxval[right]+=add[rt];
add[rt]=0;
}
}
void build(int l,int r,int rt){
add[rt]=0;
if(l==r){
maxval[rt]=t[l];
return;
}
havemid;
build(lson);
build(rson);
pushup(rt);
}
void updata(int L,int R,int c,int l,int r,int rt){
if(L<=l&&r<=R){
add[rt]+=c;
maxval[rt]+=c;
return ;
}
pushdown(rt);
havemid;
if(L<=m)updata(L,R,c,lson);
if(R>m)updata(L,R,c,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return maxval[rt];
}
pushdown(rt);
havemid;
int ret=-99999;
if(L<=m)ret=max(ret,query(L,R,lson));
if(m<R)ret=max(ret,query(L,R,rson));
return ret;
}
int main()
{
int T,n,m,k,i;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++)
scanf("%d",&fa[i]);
t[1]=0;
for(i=1;i<=k;i++)
t[1]+=fa[i];
for(i=2;i<=n-k+1;i++)
t[i]=t[i-1]-fa[i-1]+fa[i+k-1];
build(1,n-k+1,1);
while(m--)
{
int a,b,op;
scanf("%d%d%d",&op,&a,&b);
if(op==0){
updata(max(1,a-k+1),min(a,n-k+1),b-fa[a],1,n-k+1,1);
fa[a]=b;
}
else if(op==1){
updata(max(1,a-k+1),min(a,n-k+1),fa[b]-fa[a],1,n-k+1,1);
updata(max(1,b-k+1),min(b,n-k+1),fa[a]-fa[b],1,n-k+1,1);
int tt=fa[a];
fa[a]=fa[b];
fa[b]=tt;
}
else if(op==2){
int res=query(a,b-k+1,1,n-k+1,1);
printf("%d\n",res);
}
}
}
return 0;
}