题意:输入N,M,K。有N个点,每个点有一个值,然后有M个操作 0 x y 表示将x的值赋为y; 1 x y 表示将x和y互换下位置(相应值也互换) ; 2 x y 表示询问[x,y]内连续K个数和的最大值。
一开始想用每个点来建树,发现不好维护区间内连续K个数的和的最大值。
但如果转化一下,因为K是定值,将[x,x+k-1]区间的和看做一个点,这样以连续K个数和作为点,共有N-K+1的点建树。 变成了求线段树区间最值问题。
于是单点更新,转化为了区间更新: 修改了点x处的值,则产生的影响区间为 【max(1,x-k+1),min(n-k+1,x) 】。
#include <iostream>
#include <algorithm>
#include <cmath>
#include<functional>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <climits>//形如INT_MAX一类的
#define MAX 200050
#define INF 0x7FFFFFFF
#define L(x) x<<1
#define R(x) x<<1|1
# define eps 1e-5
using namespace std;
inline void RD(int &ret) {
char c;
int flag = 1 ;
do {
c = getchar();
if(c == '-')flag = -1 ;
} while(c < '0' || c > '9') ;
ret = c - '0';
while((c=getchar()) >= '0' && c <= '9')
ret = ret * 10 + ( c - '0' );
ret *= flag ;
}
void OT(int a) {
if(a < 0) {
putchar('-');
a = -a;
}
if(a >= 10)OT(a / 10);
putchar(a % 10 + '0');
}
int n,m,k;
struct node {
int l,r,mid;
int v,add;
}tr[MAX * 4];
int a[MAX],va[MAX];
void init() {
memset(va,0,sizeof(va));
}
void up(int x) {
tr[x].v = max(tr[L(x)].v, tr[R(x)].v);
}
void build(int l,int r,int x) {
tr[x].l = l;
tr[x].r = r;
tr[x].mid = (l + r) >> 1;
tr[x].add = 0;
if(l == r) {
tr[x].v = va[l];
return ;
}
build(l,tr[x].mid,L(x));
build(tr[x].mid+1,r,R(x));
up(x);
}
void down(int x) {
if(tr[x].add != 0) {
tr[L(x)].add += tr[x].add;
tr[R(x)].add += tr[x].add;
tr[L(x)].v += tr[x].add;
tr[R(x)].v += tr[x].add;
tr[x].add = 0;
}
}
void update(int l,int r,int x,int val) {
if(l <= tr[x].l && r >= tr[x].r) {
tr[x].add += val;
tr[x].v += val;
return ;
}
down(x);
int mid = tr[x].mid;
if(l <= mid) update(l,r,L(x),val);
if(r > mid) update(l,r,R(x),val);
up(x);
}
int query(int l,int r,int x) {
if(l <= tr[x].l && r >= tr[x].r) {
return tr[x].v;
}
down(x);
int mid = tr[x].mid;
if(r <= mid) return query(l,r,L(x));
else if(l > mid) return query(l,r,R(x));
else {
return max(query(l,mid,L(x)), query(mid+1,r,R(x)));
}
}
void test() {
int size = n - k + 1;
for(int i=1; i<=3 * size; i++) {
printf("%d %d %d %d\n",tr[i].l,tr[i].r,tr[i].v,tr[i].add);
}
}
int main() {
int T;
cin >> T;
while(T --) {
init();
scanf("%d%d%d",&n,&m,&k);
for(int i=1; i<=n; i++) RD(a[i]);
for(int i=1; i<=k; i++) va[1] += a[i];
for(int i=k+1; i<=n; i++) {
va[i - k + 1] = va[i - k] - a[i - k] + a[i];
}
build(1,n-k+1,1);
int b,c,d;
for(int i=0; i<m; i++) {
RD(b);RD(c);RD(d);
if(b == 0) {
int val = d - a[c];
update(max(1,c-k+1),min(n-k+1,c),1,val);
a[c] = d;
}
if(b == 1) {
if(c == d || a[c] == a[d]) continue;
int x1 = a[c] - a[d];
int x2 = a[d] - a[c];
update(max(1,c-k+1),min(n-k+1,c),1,x2);
update(max(1,d-k+1),min(n-k+1,d),1,x1);
swap(a[c],a[d]);
}
if(b == 2) {
OT(query(c,d-k+1,1));
puts("");
}
}
}
return 0;
}
/*
1
5 7 3
-1 2 -4 6 1
2 1 5
2 1 3
1 2 1
2 1 5
2 1 4
0 2 4
2 1 5
*/