題意:輸入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-5using 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;}/*15 7 3-1 2 -4 6 12 1 52 1 31 2 12 1 52 1 40 2 42 1 5*/