金华邀请赛D题,现场lazy标记推错了,颇为不爽,重做一下。

给出一个N个数的序列以及一个k(0<k<=n<=200000),m个操作p,x,y,其中

p=0:将x位置的数替换为y

p=1:将x y位置的数互换

p=2:  查询x-y位置区间连续k个数的和的最大值

很快可以想到用O(n)的复杂度预处理,将从i位置起始连续k个数的和求出来,那么对于查询操作,就变为查询和数组中x~y-k+1这个区间里的最大值。

再看对于前两种操作,第二种可以等效于两次第一种操作。对于第一种操作,将x位置由y0替换为y,变化量det=y-y0,这个变化量会对和数组产生怎样得影响呢?很明显会导致和数组的x-k+1~x这也一段产生影响,效果为值都变化det。

至此,整个问题就变成了成段修改成段查询问题。用线段数可以解决。

对于成段修改,需要用到lazy思想,即能不多改就不多改,等需要时再改。去年暑假时是做过不少各种类型的线段树的,但是区域赛后就再没写过,于是现场时就死在了这个问题上……这是客观因素,主观上也有理解的深度不够的问题……其实此题唯一算是难点的地方在于构造成适合线段树的形式,难点搞过了却卡在了实现上……

需要注意的一点是,当需要用到真实值的时候,必须先进行pushdown操作,无论在任何地方都是这样!今天第一次提交就因为在update中求最大值时没有对左右孩子进行pushdown而WA了一次……

 

  1 //10184789    NKHelloWorld    4047    Accepted    5980K    329MS    G++    2373B    2012-05-11 20:59:20
  2 #include <cstdio>
  3 #include <iostream>
  4 using namespace std;
  5 #define MAXN 210000
  6 
  7 int a[MAXN],sum[MAXN];
  8 int n,m,k;
  9 
 10 struct SEGTREE
 11 {
 12     int l,r,maxval,det;
 13 }tree[MAXN*4];
 14 
 15 void buildsegtree(int root,int l,int r)
 16 {
 17     tree[root].l = l;    tree[root].r = r;
 18     tree[root].det = 0;
 19     if(l == r)
 20     {
 21         tree[root].maxval = sum[l];
 22         return ;
 23     }
 24     int mid = (l+r)>>1;
 25     buildsegtree(root<<1,l,mid);
 26     buildsegtree(root<<1|1,mid+1,r);
 27     tree[root].maxval = max(tree[root<<1].maxval,tree[root<<1|1].maxval);
 28 }
 29 
 30 void pushdown(int root)
 31 {
 32     if(tree[root].det == 0)    return ;
 33     tree[root].maxval += tree[root].det;
 34     if(tree[root].l != tree[root].r)
 35     {
 36         tree[root<<1].det += tree[root].det;
 37         tree[root<<1|1].det += tree[root].det;
 38     }
 39     tree[root].det = 0;
 40 }
 41 
 42 void update(int root,int l,int r,int det)
 43 {
 44     pushdown(root);
 45     if(tree[root].l == l && tree[root].r == r)
 46     {
 47         tree[root].det += det;
 48         return ;
 49     }
 50     int mid = (tree[root].l + tree[root].r)>>1;
 51     if(r <= mid)
 52         update(root<<1,l,r,det);
 53     else if(l >mid)
 54         update(root<<1|1,l,r,det);
 55     else
 56     {
 57         update(root<<1,l,mid,det);
 58         update(root<<1|1,mid+1,r,det);
 59     }
 60     pushdown(root<<1);
 61     pushdown(root<<1|1);
 62     tree[root].maxval = max(tree[root<<1].maxval,tree[root<<1|1].maxval);
 63 }
 64 
 65 int query(int root,int l,int r)
 66 {
 67     pushdown(root);
 68     if(tree[root].l == l && tree[root].r == r)
 69     {
 70         return tree[root].maxval;
 71     }
 72     int mid = (tree[root].l + tree[root].r)>>1;
 73     if(r <= mid)
 74         return query(root<<1,l,r);
 75     else if(l >mid)
 76         return query(root<<1|1,l,r);
 77     else
 78         return max(query(root<<1,l,mid),query(root<<1|1,mid+1,r));
 79 }
 80 
 81 void edit(int x,int y)
 82 {
 83     int det = y - a[x];
 84     a[x] = y;
 85     int ll = x-k+1;
 86     if(ll <1)    ll = 1;
 87     int rr = x;
 88     if(x > n - k +1)    rr = n-k+1;
 89     update(1,ll,rr,det);
 90 }
 91 
 92 int main()
 93 {
 94     int totcase,i,j;
 95     scanf("%d",&totcase);
 96     while(totcase--)
 97     {
 98         scanf("%d%d%d",&n,&m,&k);
 99         for(i=1;i<=n;i++)
100         {
101             scanf("%d",&a[i]);
102         }
103         sum[1] = 0;
104         for(i=1;i<=k;i++)    sum[1] += a[i];
105         for(i=2;i<=n-k+1;i++)    sum[i] = sum[i-1] - a[i-1] + a[i+k-1];
106         buildsegtree(1,1,n-k+1);
107         int p,x,y;
108         while(m--)
109         {
110             scanf("%d%d%d",&p,&x,&y);
111             if(p==0)
112             {
113                 edit(x,y);
114             }
115             else if(p ==1 )
116             {
117                 int xx = a[x],yy = a[y];
118                 edit(y,xx);
119                 edit(x,yy);
120             }
121             else
122             {
123                 printf("%d\n",query(1,x,y-k+1));
124             }
125         }
126     }
127     return 0;
128 }
posted on 2012-05-11 21:25  NKHe!!oWor!d  阅读(578)  评论(0编辑  收藏  举报