/* 題意:
給出一個N個數的序列以及一個k(0<k<=n<=200000),m個操作p,x,y,其中
p=0:將x位置的數替換爲y
p=1:將x y位置的數互換
p=2: 查詢x-y位置區間連續k個數的和的最大值
解析:求連續區間和最大,可以講每個區間(我們取左端點)當做一個點,點的附加信息(線段樹結子葉點的值)
就等於該區間的連續k個數最大值,可以分爲1~k,2~k+1...n-k+1~n,一共從1到n-k+1個點構成線段樹。
線段樹中除了子葉結點,其他結點都保存的是子葉結點中的最大值。
當x位置值改變時,影響的範圍爲:
注:我們都是以區間的左端點存入線段樹;
(1)假設x位置是某區間的右端點,則其左端點爲x-k+1,但是最小端點是從1開始,
x-k+1可能小於1,因此要取這兩者最大值;
(2)假設x位置是某區間的左端點,再次說明下,我們是以區間的左端點代表該區間存入線段樹,因此當x爲左端點
時要與最大左端點n-k+1比較,取最小值;
求出x位置影響範圍後,更新區間[max(1,x-k+1),min(x,n-k+1)],找到更新結點後,回溯向上更新即Getmax函數,
當p==1時,區間最值變爲_max=_max-v[x]+y;
當p==2時,相當於兩次p==1的操作,_max=_max-v[x]+v[y],_max=_max-v[y]+v]x];
每次某位置值改變後,要在原數組中同時更改
最後查詢x到y位置區間最值時,我們是以區間左端點代表區間,在線段樹中只需查詢l=x,r=y-k+1即可
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define mem0(a) memset(a,0,sizeof(a))
const int maxn = 200000+10;
int sum;
int v[maxn],b[maxn];
struct node{
int l,r,_max,lazy;
}a[maxn<<2];
void Getmax(int cur){
a[cur]._max = max(a[cur<<1]._max,a[cur<<1|1]._max);
}
void build(int l,int r,int cur){
a[cur].l = l;
a[cur].r = r;
a[cur].lazy = 0;
int mid = (l + r )>>1;
if(l == r){
a[cur]._max = b[l];
return ;
}
build(l,mid,cur<<1);
build(mid+1,r,cur<<1|1);
Getmax(cur);
}
void pushdown(int cur){
if(a[cur].lazy){
//設置左右孩子節點的標誌域,因爲孩子節點可能被多次延遲標記又沒有向下傳遞
//所以是 “+=”
a[cur<<1].lazy += a[cur].lazy;
a[cur<<1|1].lazy += a[cur].lazy;
//根據標誌域設置孩子節點的值。因爲我們是求區間最大值,因此當區間內每個元
//素加上一個值時,區間的最大值也加上這個值
a[cur<<1]._max += a[cur].lazy;
a[cur<<1|1]._max += a[cur].lazy;
a[cur].lazy = 0;//清除標記
}
}
void update(int l,int r,int v,int cur){
//當前節點區間包含在更新區間內
if( l <= a[cur].l && r >= a[cur].r){
a[cur]._max += v;
a[cur].lazy += v;
return ;
}
pushdown(cur); //延遲標記向下傳遞
//更新左右孩子節點
int mid = (a[cur].l + a[cur].r )>>1;
if(r <= mid)
update(l,r,v,cur<<1);
else if(l > mid)
update(l,r,v,cur<<1|1);
else {
update(l,mid,v,cur<<1);
update(mid+1,r,v,cur<<1|1);
}
Getmax(cur);//根據左右子樹的值回溯更新當前節點的值
}
int query(int l,int r,int cur){
if( l <= a[cur].l && r >= a[cur].r){
return a[cur]._max;
}//若等於要求的區間,則返回結點保存的最值
pushdown(cur);//----延遲標誌域向下傳遞
int mid = (a[cur].l + a[cur].r )>>1;
//分別從左右子樹查詢,返回兩者查詢結果的較大值
if(r <= mid )
return query(l,r,cur<<1);
else if(l > mid)
return query(l,r,cur<<1|1);
else {
return max(query(l,mid,cur<<1),query(mid+1,r,cur<<1|1));
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1 ;i <= n ; i++)
scanf("%d",&v[i]);
mem0(b);
for(int i = 1 ; i <= k ; i++)
b[1]+=v[i];//第一段和,從1~k
for(int i = 2 ; i <= n-k+1;i++)
b[i]=b[i-1]-v[i-1]+v[i+k-1];
//求剩下每k段和,2~k+1...n-k+1~n
build(1,n-k+1,1);
while(m--){
int c,x,y;
scanf("%d%d%d",&c,&x,&y);
if(c==0){
update(max(1,x-k+1),min(n-k+1,x),y-v[x],1);
v[x]=y;
}
else if(c== 1){
update(max(1,x-k+1),min(n-k+1,x),v[y]-v[x],1);
update(max(1,y-k+1),min(n-k+1,y),v[x]-v[y],1);
swap(v[x],v[y]);
}
else
printf("%d\n",query(x,y-k+1,1));
}
}
return 0;
}
poj_4047Garden區間更新_求和
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.