【线段树 经典技巧】10.7序列绝对值

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

不过稍微有些细节

题目大意

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

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

$n,q\le 10^5$,保证$1<l\le 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\n",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

posted @ 2019-10-07 16:00  AntiQuality  阅读(267)  评论(0编辑  收藏  举报