zoukankan      html  css  js  c++  java
  • 【线段树 经典技巧】10.7序列绝对值

    依旧是经典的线段树处理新定义权值以及拆绝对值技巧

    不过稍微有些细节

    题目大意

    初始先给定一个序列$A$,定义一个序列的绝对权值为$sumlimits_{i=2}^n|a_i-a_{i-1}|$.

    现在有$q$次操作,每个操作或是询问如果在$A[l,r]$任选一个数加上$x$,$A$的绝对权值最大是多少;或区间加。

    $n,qle 10^5$,保证$1<lle r<n$.


    题目分析

    首先这是一个经典的线段树处理新定义权值最值的问题。

    考虑一个$i$位置权值为$B$,它的左右权值分别是$A,C$,那么现在如果把它变成数$X$,为答案造成的贡献就是$(|X-A|+|X-C|)-(|B-A|+|B-C|)$.

    定义$wrin(i)=(|B-A|+|B-C|)$,处理后贡献式子就是

    $=max{A+C-2*X,-A-C+2*X,(max{A,C}-min{A,C})}-wrin(i)$

    其中对于每一个位置来说,$A+C$或者$|A-C|$都是方便维护的常量。因此只需要记录区间内$max{A+C},max{-A-C},max{|A-C|}$这三个量就能够处理询问了。

    接下来考虑如何修改。

    对于修改的区间$[L,R]$,它对上述的三个量都会在$L-1,L,R,R+1$四个单点位置有变化,并且前两个量还有$[L,R]$的整段增量。也就是说要维护区间/单点加和区间最大值的线段树。

    还有一个小点就是要处理每次修改后的全局权值,也就是说要询问某一位置元素的权值。这个由于对区间元素的修改是区间的,而查询元素是单点的,所以用树状数组累计一下差分后的数组就好了。

      1 #include<bits/stdc++.h>
      2 typedef long long ll;
      3 const int maxn = 100035;
      4 
      5 int n,q;
      6 ll ans,val,a[maxn],num[maxn];
      7 ll abs(ll x){return x > 0?x:-x;}
      8 struct SegTree
      9 {
     10     ll f[maxn<<2],add[maxn<<2];
     11     
     12     void pushup(int rt)
     13     {
     14         f[rt] = std::max(f[rt<<1], f[rt<<1|1]);
     15     }
     16     void pushdown(int rt)
     17     {
     18         if (add[rt]){
     19             int l = rt<<1, r = rt<<1|1;
     20             ll &tag = add[rt];
     21             add[l] += tag, add[r] += tag;
     22             f[l] += tag, f[r] += tag, tag = 0;
     23         }
     24     }
     25     void build(int rt, int l, int r, ll c)
     26     {
     27         if (l==r){
     28             f[rt] = (a[l-1]+a[l+1])*c-abs(a[l]-a[l-1])-abs(a[l]-a[l+1])-2*c*a[l];
     29             if (c==0) f[rt] = abs(a[l+1]-a[l-1])-abs(a[l]-a[l-1])-abs(a[l]-a[l+1]);
     30         }else{
     31             int mid = (l+r)>>1;
     32             build(rt<<1, l, mid, c);
     33             build(rt<<1|1, mid+1, r, c);
     34             pushup(rt);
     35         }
     36     }
     37     void modify(int rt, int L, int R, int l, int r, ll c)
     38     {
     39         if (L <= l&&r <= R){
     40             f[rt] += c, add[rt] += c;
     41         }else{
     42             int mid = (l+r)>>1;
     43             pushdown(rt);
     44             if (L <= mid) modify(rt<<1, L, R, l, mid, c);
     45             if (R > mid) modify(rt<<1|1, L, R, mid+1, r, c);
     46             pushup(rt);
     47         }
     48     }
     49     void modify(int rt, int l, int r, int pos, ll c)
     50     {
     51         if (l==r) f[rt] += c;
     52         else{
     53             int mid = (l+r)>>1;
     54             pushdown(rt);
     55             if (pos <= mid) modify(rt<<1, l, mid, pos, c);
     56             else modify(rt<<1|1, mid+1, r, pos, c);
     57             pushup(rt);
     58         }
     59     }
     60     ll query(int rt, int L, int R, int l, int r)
     61     {
     62         if (L <= l&&r <= R) return f[rt];
     63         int mid = (l+r)>>1;
     64         ll ret = -(1ll<<60);
     65         pushdown(rt);
     66         if (L <= mid) ret = query(rt<<1, L, R, l, mid);
     67         if (R > mid) ret = std::max(ret, query(rt<<1|1, L, R, mid+1, r));
     68         return ret;
     69     }
     70 }f,g,h;
     71 
     72 int read()
     73 {
     74     char ch = getchar();
     75     int num = 0, fl = 1;
     76     for (; !isdigit(ch); ch=getchar())
     77         if (ch=='-') fl = -1;
     78     for (; isdigit(ch); ch=getchar())
     79         num = (num<<1)+(num<<3)+ch-48;
     80     return num*fl;
     81 }
     82 void add(int x, ll c){for (; x<=n; x+=x&-x) num[x] += c;}
     83 ll query(int x)                                //之前这里query类型写成int...
     84 {
     85     ll ret = 0;
     86     for (; x; x-=x&-x) ret += num[x];
     87     return ret;
     88 }
     89 int main()
     90 {
     91     n = read(); 
     92     for (int i=1; i<=n; i++) a[i] = read();
     93     for (int i=1; i<=n; i++)
     94         add(i, a[i]-a[i-1]), 
     95         val += i!=n?abs(a[i]-a[i+1]):0;
     96     f.build(1, 1, n, 1);
     97     g.build(1, 1, n, -1);
     98     h.build(1, 1, n, 0);
     99     q = read();
    100     for (int opt,l,r,x; q; --q)
    101     {
    102         opt = read(), l = read(), r = read(), x = read();
    103         if (opt==1){
    104             ans = std::max(h.query(1, l, r, 1, n), std::max(f.query(1, l, r, 1, n)-2ll*x, g.query(1, l, r, 1, n)+2ll*x))+val;
    105             printf("%lld
    ",ans);
    106         }else{
    107             f.modify(1, l, r, 1, n, -2ll*x);
    108             g.modify(1, l, r, 1, n, 2ll*x);
    109             f.modify(1, l-1, r-1, 1, n, x);
    110             g.modify(1, l+1, r+1, 1, n, -x);
    111             f.modify(1, l+1, r+1, 1, n, x);
    112             g.modify(1, l-1, r-1, 1, n, -x);
    113             ll p1 = query(l-1), p2 = query(l), p3 = query(r), p4 = query(r+1), det = 0;
    114             det = abs(p1-p2-x)-abs(p1-p2), val += det;                //-----wrin-----
    115             f.modify(1, 1, n, l-1, -det);
    116             g.modify(1, 1, n, l-1, -det);
    117             h.modify(1, 1, n, l-1, -det);
    118             f.modify(1, 1, n, l, -det);
    119             g.modify(1, 1, n, l, -det);
    120             h.modify(1, 1, n, l, -det);
    121             det = abs(p4-p3-x)-abs(p4-p3), val += det;
    122             f.modify(1, 1, n, r+1, -det);
    123             g.modify(1, 1, n, r+1, -det);
    124             h.modify(1, 1, n, r+1, -det);
    125             f.modify(1, 1, n, r, -det);
    126             g.modify(1, 1, n, r, -det);
    127             h.modify(1, 1, n, r, -det);                                //-----wrin-----
    128             ll p5 = query(l-2), p6 = query(l+1), p7 = query(r-1), p8 = query(r+2);  //容易写成a[..]
    129             det = abs(p5-p2)-abs(p5-p2-x);          //因为左右两个元素并不知道大小关系
    130             h.modify(1, 1, n, l-1, -det);
    131             if (l!=r){
    132                 det = abs(p1-p6)-abs(p1-p6-x);
    133                 h.modify(1, 1, n, l, -det);
    134                 det = abs(p4-p7)-abs(p4-p7-x);
    135                 h.modify(1, 1, n, r, -det);
    136             }
    137             det = abs(p8-p3)-abs(p8-p3-x);
    138             h.modify(1, 1, n, r+1, -det);
    139             add(l, x), add(r+1, -x);
    140         }
    141     }
    142     return 0;
    143 } 

    END

  • 相关阅读:
    打包和调试静态库(2)
    打包和调试静态库(1)
    Xcode7--免证书真机调试
    开发者账号申请附录
    AFN3.0封装
    MPMoviePlayerController属性,方法,通知整理
    排序算法03--选择排序
    排序算法02--冒泡排序
    遇到别人留下的storyboard的,你需要一个引导图,但是不知道怎么跳转.
    将UIview描画成虚线等.
  • 原文地址:https://www.cnblogs.com/antiquality/p/11630722.html
Copyright © 2011-2022 走看看