POJ 4047 Garden (線段樹)

題意:輸入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
*/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章