2012金华邀请赛 Problem D. Garden 线段树题目

又是一个线段树问题,做了那么多的线段树,遇到这个题,还真是好难为我啊,看了好久都没看出来怎么做!

看了很久思维只局限在单点更新上,怎么想都是死胡同,直到,突然闪电击中了大脑,然后,然后,原来这个题是区间更新,(#‵′)靠。

具体的思路是:每个点和其后面的k个点的和算作一个点,然后,更新的时候,更新影响到的点,查询的时候,查询需查询区间的多有相应的点的最值即可!

这个题的关键是区间更新,一个点的变化,他会影响到k个处理好的点!

想出来思路就知道为什么这个题的k是固定的了!也只有k是固定的,才能想出用这种方法! 

其实,题目中往往会隐藏很多可以思考的点,例如,这个题目中的固定的k,有时候,思考点是给的是不大的数据,当然,时间复杂度成为了基本的知识点!

最近我越来越觉得,真正的比赛,不仅看你学到多少,会了多少东西,最重要的是,看你赛场上能够想起多少东西。然后我就想起来了《暗时间》中说的。其实记忆这个东西,很奇怪,他只是建立了一些神经元的突起,真正让你回忆起来的是一些所谓的“线索”,当抓到这些线索,你就能拽出很多东西,使劲刷题切题的时候,注意多建立一些“线索”,到比赛的时候好有的拽!哈哈,简单来说,就是多想、多学、多总结,多做笔记。总之就是,你记住的,但是用得着的时候想不起来的东西,只能说你没记住!

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define N 200010
int dat[N],sum[N];

int n,m,k;
///线段树 区间更新 区间最值
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fmid int m = (l+r)>>1

int ma[N*4],cnt[N*4];

void Push_up(int rt)
{
    ma[rt] = max(ma[rt<<1],ma[rt<<1|1]);
}
void Push_down(int rt)
{
    if(cnt[rt] != 0)
    {
        ma[rt<<1]    += cnt[rt];
        ma[rt<<1|1]  += cnt[rt];
        cnt[rt<<1]   += cnt[rt];
        cnt[rt<<1|1] += cnt[rt];
        cnt[rt] = 0;
    }
}
void build(int l,int r,int rt)
{
    cnt[rt] = 0;
    if(l == r)
    {
        ma[rt] = sum[l+k-1] - sum[l-1];
        return ;
    }
    fmid;
    build(lson);
    build(rson);
    Push_up(rt);
}
void update(int L,int R,int val,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
        cnt[rt] += val;
        ma[rt] += val;
        return ;
    }
    Push_down(rt);
    fmid;
    if(L <= m) update(L,R,val,lson);
    if(m < R) update(L,R,val,rson);
    Push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
        return ma[rt];
    }
    Push_down(rt);
    fmid;
    int re = -999999999;
    //cout << re << " ";
    if(L <= m) re = max(re,query(L,R,lson));
    if(m < R) re = max(re,query(L,R,rson));
    return re;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {

        scanf("%d%d%d",&n,&m,&k);
        for(int i = 1;i <= n;i++) scanf("%d",&dat[i]);
        sum[0] = 0;
        for(int i = 1;i <= n;i++) sum[i] = sum[i-1] + dat[i];

        build(1,n-k+1,1);

        int p,x,y;
        while(m--)
        {
            scanf("%d%d%d",&p,&x,&y);
            if(p == 0)
            {
                update(max(1,x - k + 1),min(x,n-k+1),y - dat[x],1,n-k+1,1);
                dat[x] = y;
            }else if(p == 1)
            {
                update(max(1,x - k + 1),min(x,n-k+1),dat[y] - dat[x],1,n-k+1,1);
                update(max(1,y - k + 1),min(y,n-k+1),dat[x] - dat[y],1,n-k+1,1);
                int t = dat[x];dat[x] = dat[y];dat[y] = t;
            }else
            {
                int tt = query(x,y-k+1,1,n-k+1,1);
                printf("%d\n",tt);
            }
        }
    }
    return 0;
}


你可能感兴趣的:(2012金华邀请赛 Problem D. Garden 线段树题目)