线段树中区间加减和区间覆盖的双标记问题

HDU 5828

吉老师真厉害。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define lson q << 1
  4 #define rson (q << 1) | 1
  5 #define mid ((l + r) >> 1)
  6 typedef long long ll;
  7 const int maxn = 1e5 + 50;
  8 ll maxv[maxn << 2];
  9 ll minv[maxn << 2];
 10 ll sum[maxn << 2];
 11 ll lazy[maxn << 2];
 12 ll cover[maxn << 2];
 13 int segl[maxn << 2], segr[maxn << 2];
 14 int a[maxn];
 15 void push_up(int q)
 16 {
 17     maxv[q] = max(maxv[lson], maxv[rson]);
 18     minv[q] = min(minv[lson], minv[rson]);
 19     sum[q] = sum[lson] + sum[rson];
 20 }
 21 void build(int q, int l, int r)
 22 {
 23     lazy[q] = cover[q] = 0;
 24     segl[q] = l, segr[q] = r;
 25     maxv[q] = minv[q] = sum[q] = 0;
 26     if(l == r)
 27     {
 28         sum[q] = maxv[q] = minv[q] = a[l];
 29         return;
 30     }
 31     build(lson, l, mid);
 32     build(rson, mid + 1, r);
 33     push_up(q);
 34 }
 35 void push_down(int q)
 36 {
 37     if(cover[q])
 38     {
 39         maxv[lson] = minv[lson] = cover[q] + lazy[q];
 40         cover[lson] = minv[lson];
 41         sum[lson] = (ll)(segr[lson] - segl[lson] + 1) * minv[lson];
 42         maxv[rson] = minv[rson] = cover[q] + lazy[q];
 43         cover[rson] = minv[rson];
 44         sum[rson] = (ll)(segr[rson] - segl[rson] + 1) * minv[rson];
 45         lazy[q] = cover[q] = lazy[lson] = lazy[rson] = 0;
 46     }
 47     else if(lazy[q])
 48     {
 49         lazy[lson] += lazy[q];
 50         minv[lson] += lazy[q];
 51         maxv[lson] += lazy[q];
 52         sum[lson] += (ll)(segr[lson] - segl[lson] + 1) * lazy[q];
 53         lazy[rson] += lazy[q];
 54         minv[rson] += lazy[q];
 55         maxv[rson] += lazy[q];
 56         sum[rson] += (ll)(segr[rson] - segl[rson] + 1) * lazy[q];
 57         lazy[q] = 0;
 58     }
 59 }
 60 void change(int q, int l, int r, int ql, int qr, int x)
 61 {
 62     if(qr < l || ql > r) return;
 63     if(ql <= l && qr >= r)
 64     {
 65         lazy[q] += x;
 66         maxv[q] += x;
 67         minv[q] += x;
 68         sum[q] += (ll)(r - l + 1) * x;
 69         return;
 70     }
 71     push_down(q);
 72     change(lson, l, mid, ql, qr, x);
 73     change(rson, mid + 1, r, ql, qr, x);
 74     push_up(q);
 75 }
 76 void change(int q, int l, int r, int ql, int qr)
 77 {
 78     if(qr < l || ql > r) return;
 79     if(ql <= l && qr >= r && maxv[q] - minv[q] <= 1LL)
 80     {
 81         if(maxv[q] == minv[q] || (ll)sqrt(maxv[q]) == (ll)sqrt(minv[q]))
 82         {
 83             maxv[q] = minv[q] = sqrt(minv[q]);
 84             cover[q] = maxv[q];
 85             lazy[q] = 0;
 86             sum[q] = (ll)(r - l + 1) * maxv[q];
 87         }
 88         else
 89         {
 90             lazy[q] += -1LL * (minv[q] - (ll)sqrt(minv[q]));
 91             sum[q] -= (ll)(r - l + 1) * (minv[q] - (ll)sqrt(minv[q]));
 92             minv[q] = sqrt(minv[q]);
 93             maxv[q] = minv[q] + 1;
 94         }
 95         return;
 96     }
 97     push_down(q);
 98     change(lson, l, mid, ql, qr);
 99     change(rson, mid + 1, r, ql, qr);
100     push_up(q);
101 }
102 ll query(int q, int l, int r, int ql, int qr)
103 {
104     if(qr < l || ql > r) return 0;
105     if(ql <= l && qr >= r)
106     {
107         return sum[q];
108     }
109     push_down(q);
110     ll ret = 0;
111     ret += query(lson, l, mid, ql, qr);
112     ret += query(rson, mid + 1, r, ql, qr);
113     return ret;
114 }
115 int main()
116 {
117     int T; scanf("%d", &T);
118     while(T--)
119     {
120         int n, m; scanf("%d %d", &n, &m);
121         for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
122         build(1, 1, n);
123         for(int i = 1; i <= m; i++)
124         {
125             int type, l, r, x;
126             scanf("%d", &type);
127             if(type == 1)
128             {
129                 scanf("%d %d %d", &l, &r, &x);
130                 change(1, 1, n, l, r, x);
131             }
132             else if(type == 2)
133             {
134                 scanf("%d %d", &l, &r);
135                 change(1, 1, n, l, r);
136             }
137             else if(type == 3)
138             {
139                 scanf("%d %d", &l, &r);
140                 printf("%lld\n", query(1, 1, n, l, r));
141             }
142         }
143     }
144     return 0;
145 }

原文地址:https://www.cnblogs.com/wangwangyu/p/9880271.html

时间: 2024-11-13 07:51:58

线段树中区间加减和区间覆盖的双标记问题的相关文章

二维树状数组的区间加减及查询 tyvj 1716 上帝造题的七分钟

具体解释见小结.http://blog.csdn.net/zmx354/article/details/31740985 #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <stack>

POJ 3468 A Simple Problem with Integers(线段树功能:区间加减区间求和)

题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 56005   Accepted: 16903 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with

poj3468区间加减查找——树状数组区间修改查询

题目:http://poj.org/problem?id=3468 增加一个更改量数组,施以差值用法则区间修改变为单位置修改: 利用公式可通过树状数组维护两个数组:f与g而直接求出区间和. 代码如下: #include<iostream> #include<cstdio> using namespace std; long long n,q,a[100005]/*,b[100005],bg[100005]*/,l,r,ad; long long f[100005],g[100005

POJ 3468 区间加减 区间求和

1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define lson l,m,rt<<1 6 #define rson m+1,r,rt<<1|1 7 #define INF 0x7fffffff 8 #define maxn 101000 9 #define LL long long 10 using name

算法模板——线段树4(区间加+区间乘+区间覆盖值+区间求和)

实现功能——1:区间加法 2:区间乘法 3:区间覆盖值 4:区间求和 这是个四种常见线段树功能的集合版哦...么么哒(其实只要协调好三种tag的关系并不算太难——前提是想明白了线段树的工作模式) 代码长度几经修改后也大为缩水 还有!!!——通过BZOJ1798反复的尝试,我的出来一个重要结论——尽量减少pushup操作的不必要使用次数,对于程序提速有明显的效果!!! 1 type vet=record 2 a0,a1:longint; 3 end; 4 var 5 i,j,k,l,m,n,a1,

vijos 1659 河蟹王国 线段树区间加、区间查询最大值

河蟹王国 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 https://vijos.org/p/1659 Description 河蟹王国有一位河蟹国王,他的名字叫羊驼.河蟹王国富饶安定,人们和谐相处.有一天,羊驼国王心血来潮,想在一部分人中挑出最和谐的人.于是,羊驼国王将 他的子民排成了一列(==!!b汗~好长呀).每个人都有一个初始的和谐值.羊驼国王每次会选择一个区间[L,R],这个区间中和谐值最大的人就是国王选 出的人.而且,在某一时间,区间[L

线段树_区间加乘(洛谷P3373模板)

题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字的个数.操作的总个数和模数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k 操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

线段树の二 区间乘+区间加

具体就不解释了,看上一篇文章 放代码 注意点:!!!! 注意运算符优先级 比如: a*=b%p 是b先mod p再与a相乘 参见:https://baike.baidu.com/item/%E8%BF%90%E7%AE%97%E7%AC%A6%E4%BC%98%E5%85%88%E7%BA%A7/4752611?fr=aladdin /******************************* 线段树V2.0 支持区间加.区间乘.区间和查询 *************************

「模板」 线段树——区间乘 &amp;&amp; 区间加 &amp;&amp; 区间求和

「模板」 线段树--区间乘 && 区间加 && 区间求和 <题目链接> 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long long p; class SegmentTree { private: struct Node { int l,r; long long v,mul,add; Node *c[2]; Node(int l,int r):l(l),r(r),mul(1LL),add(0LL) { c[