POJ 4047 Garden 线段树 区间更新

给出一个n个元素的序列,序列有正数也有负数

支持3个操作:

p x y

0.p=0时,把第x个的值改为y

1.p=1时,交换第x个和第y个的值

2.p=2时,问区间[x,y]里面连续k个的子序列的最大和(保证y-x+1>=k)

我们只要定义数组v

v[i]表示原序列中,从第i个开始,连续k个元素的值的和

然后我们只需要维护一棵线段树,树的叶子节点表示数组v

树的节点维护:

区间[l,r]中,连续k个的子序列的最大和,即数组v的最大值

这样的话,3个操作就变为:

0.把区间[max(x-k+1,0),x]的值加y-init_v[x]

1.区间[max(x-k+1,0),x]加上init_v[y]-init_v[x]

 区间[max(y-k+1,0),y]加上init_v[x]-init_v[y]

 交换init_v[x]和init_v[y]的值

2.求max[x,y-k+1]

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4
  5 using namespace std;
  6
  7 #define ll long long
  8 #define lson l,m,rt<<1
  9 #define rson m+1,r,rt<<1|1
 10
 11 const int maxn=200000+5;
 12 const int inf=0x3f3f3f3f;
 13
 14 int init_v[maxn];
 15 int init_sum[maxn];
 16 int v[maxn<<2];
 17 int lazy[maxn<<2];
 18 int n,m,k;
 19
 20 void solve();
 21
 22 int main()
 23 {
 24     int test;
 25     scanf("%d",&test);
 26     while(test--){
 27         scanf("%d %d %d",&n,&m,&k);
 28         for(int i=1;i<=n;i++){
 29             scanf("%d",&init_v[i]);
 30         }
 31         solve();
 32     }
 33     return 0;
 34 }
 35
 36 void pushup(int rt)
 37 {
 38     v[rt]=max(v[rt<<1],v[rt<<1|1]);
 39 }
 40
 41 void pushdown(int rt)
 42 {
 43     if(lazy[rt]){
 44         lazy[rt<<1]+=lazy[rt];
 45         lazy[rt<<1|1]+=lazy[rt];
 46         v[rt<<1]+=lazy[rt];
 47         v[rt<<1|1]+=lazy[rt];
 48         lazy[rt]=0;
 49     }
 50 }
 51
 52 void build(int l,int r,int rt)
 53 {
 54     if(l==r){
 55         v[rt]=init_sum[l+k-1]-init_sum[l-1];
 56         return ;
 57     }
 58     int m=(l+r)>>1;
 59     build(lson);
 60     build(rson);
 61     pushup(rt);
 62 }
 63
 64 void update(int L,int R,int add,int l,int r,int rt)
 65 {
 66     if(L<=l&&R>=r){
 67         lazy[rt]+=add;
 68         v[rt]+=add;
 69         return ;
 70     }
 71     int m=(l+r)>>1;
 72     pushdown(rt);
 73     if(L<=m)
 74         update(L,R,add,lson);
 75     if(R>m)
 76         update(L,R,add,rson);
 77     pushup(rt);
 78 }
 79
 80 int query(int L,int R,int l,int r,int rt)
 81 {
 82     if(L<=l&&R>=r){
 83         return v[rt];
 84     }
 85     int m=(l+r)>>1;
 86     pushdown(rt);
 87     int ret=-inf;
 88     if(L<=m)
 89         ret=max(ret,query(L,R,lson));
 90     if(R>m)
 91         ret=max(ret,query(L,R,rson));
 92
 93     return ret;
 94 }
 95
 96 void solve()
 97 {
 98     init_sum[0]=0;
 99     for(int i=1;i<=n;i++){
100         init_sum[i]=init_sum[i-1]+init_v[i];
101     }
102
103     build(1,n,1);
104     memset(lazy,0,sizeof lazy);
105     for(int i=1;i<=m;i++){
106         int p,x,y;
107         scanf("%d %d %d",&p,&x,&y);
108         if(p==0){
109             update(max(x-k+1,0),x,y-init_v[x],1,n,1);
110             init_v[x]=y;
111         }
112         else if(p==1){
113             update(max(x-k+1,0),x,init_v[y]-init_v[x],1,n,1);
114             update(max(y-k+1,0),y,init_v[x]-init_v[y],1,n,1);
115             swap(init_v[x],init_v[y]);
116         }
117         else{
118             printf("%d\n",query(x,y-k+1,1,n,1));
119         }
120     }
121     return ;
122 }
时间: 2024-10-17 01:12:49

POJ 4047 Garden 线段树 区间更新的相关文章

poj 3468(简单线段树区间更新)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 61936   Accepted: 18934 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

poj 4047 Garden 线段树lazy标记与成段更新

题意: 给长度为n的序列及k(0<k<=n<=200000),m个操作p,x,y.其中(1)p==0:将x位置处的数变为y;(2)p==1:将x,y位置处的数互换.(3)p==2查询x-y位置之间连续k个数的和的最大值. 分析: 求连续区间的和最大,可以把区间看成一个点,这样这n-k+1个区间的最大和可以看做n-k+1个点的最大值,当更新原序列中位置x的值就相当于更新区间中x-k+1到x区间的值,然后用线段树做成段更新.成段更新要用到lazy标记,我的理解是:当更新或query的时候如果

POJ 2528 Mayor&#39;s posters (线段树区间更新+离散化)

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

POJ 3468 A Simple Problem with Integers(线段树区间更新)

题目地址:POJ 3468 打了个篮球回来果然神经有点冲动..无脑的狂交了8次WA..居然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题.区间更新就是加一个lazy标记,延迟标记,只有向下查询的时候才将lazy标记向下更新.其他的均按线段树的来就行. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <math.h> #include <stac

线段树 + 区间更新 + 模板 ---- poj 3468

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 59798   Accepted: 18237 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

线段树区间更新+向量知识——POJ 2991

对应POJ题目:点击打开链接 Crane Time Limit: 2000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description ACM has bought a new crane (crane -- je?áb) . The crane consists of n segments of various lengths, connected by flexible joints

poj 3468 A Simple Problem with Integers (线段树区间更新入门)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 70442   Accepted: 21723 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

poj 2777 Count Color (线段树区间更新)

Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 37647   Accepted: 11315 Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.