- 线段树维护区间和,区间更新乘与加
需要注意lazy标记的更新顺序 - 经典例题 P3373
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)
template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
const int N = 1e5 + 5;
int n , m , mod;
struct node {
int l , r;
ll sum , alz, mlz;
}tree[N * 4];
int input[N];
void build (int i , int l , int r)
{
tree[i].l = l;
tree[i].r = r;
tree[i].mlz = 1 , tree[i].alz = 0;
if (l == r)
{
tree[i].sum = input[l]%mod;
return ;
}
int mid = (l + r) >> 1;
build (i << 1 , l , mid);
build (i << 1 | 1 , mid + 1, r);
tree[i].sum = (tree[i << 1].sum + tree[i << 1 | 1].sum)%mod;
}
void pushdown (int i)
{
tree[i*2].sum = (1ll * (tree[i].mlz * tree[i*2].sum)%mod + (1ll * (tree[i*2].r-tree[i*2].l+1) * tree[i].alz)%mod)%mod;
tree[i*2+1].sum = (1ll * (tree[i].mlz * tree[i*2+1].sum)%mod + (1ll*(tree[i*2+1].r-tree[i*2+1].l+1)*tree[i].alz)%mod)%mod;
tree[i*2].mlz = 1ll*(tree[i*2].mlz*tree[i].mlz)%mod;
tree[i*2+1].mlz = 1ll*(tree[i*2+1].mlz*tree[i].mlz)%mod;
tree[i*2].alz=1ll*(tree[i*2].alz*tree[i].mlz+tree[i].alz)%mod;
tree[i*2+1].alz=1ll*(tree[i*2+1].alz*tree[i].mlz+tree[i].alz)%mod;
tree[i].mlz=1,tree[i].alz=0;
}
void Aupdate (int i , int l , int r, int k)
{
if (tree[i].l >= l && tree[i].r <= r)
{
tree[i].alz += k;
tree[i].alz %= mod;
tree[i].sum += 1ll * (tree[i].r - tree[i].l + 1) * k;
tree[i].sum %= mod;
return ;
}
pushdown(i);
int mid = (tree[i].l + tree[i].r) >> 1;
if (l <= mid) Aupdate(i << 1, l , r, k);
if (r > mid) Aupdate (i << 1 | 1 , l , r, k);
tree[i].sum = (tree[i << 1].sum + tree[i << 1 | 1].sum)%mod;
}
void Mupdate (int i , int l , int r, int k)
{
if (tree[i].l >= l && tree[i].r <= r)
{
tree[i].alz = (tree[i].alz * k) % mod;
tree[i].mlz = (tree[i].mlz * k) % mod;
tree[i].sum = (tree[i].sum * k) % mod;
return ;
}
pushdown(i);
int mid = (tree[i].l + tree[i].r) >> 1;
if (l <= mid) Mupdate(i << 1 , l , r, k);
if (r > mid) Mupdate (i << 1 | 1 , l , r, k);
tree[i].sum = (tree[i << 1].sum + tree[i << 1 | 1].sum) % mod;
}
ll query(int i , int l ,int r)
{
if(tree[i].l>=l && tree[i].r<=r){
return tree[i].sum;
}
pushdown(i);
ll val = 0;
int mid = (tree[i].l+tree[i].r)>>1;
if(l <= mid)val = (val + query(i*2,l,r))%mod;
if(mid < r)val = (val + query(i*2+1,l,r))%mod;
return val;
}
int main (void)
{
read (n , m, mod);
for (int i = 1 ; i <= n ; i ++)
read (input[i]);
build (1, 1, n);
while (m --)
{
int op , x , y , k;
read (op);
if (op == 1)
{
read (x , y, k);
Mupdate(1,x,y,k);
}
else if (op == 2)
{
read (x, y , k);
Aupdate(1,x,y,k);
}
else
{
read (x , y);
cout << query(1,x,y) << endl;
}
}
}
- 线段树区间合并,一般将区间分割为前缀,后缀,当前属性之类
经典例题:P6492
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)
template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
const int N = 3e5 + 5;
int n , m;
struct node {
int l , r;
int v , lv , rv;
int lc , rc;
}tree[N * 4];
void pushup (int i)
{
int L_len = tree[i<<1].r - tree[i<<1].l + 1;
int R_len = tree[i<<1|1].r - tree[i<<1|1].l + 1;
if (tree[i<<1].lv == L_len && tree[i<<1].rc != tree[i<<1|1].lc)
tree[i].lv = L_len + tree[i<<1|1].lv;
else
tree[i].lv = tree[i<<1].lv;
tree[i].lc = tree[i<<1].lc;
if (tree[i<<1|1].rv == R_len && tree[i<<1|1].lc != tree[i<<1].rc)
tree[i].rv = R_len + tree[i<<1].rv;
else
tree[i].rv = tree[i<<1|1].rv;
tree[i].rc = tree[i << 1 | 1].rc;
tree[i].v = 1;
tree[i].v = max (tree[i].v , tree[i<<1].v);
tree[i].v = max (tree[i].v , tree[i<<1|1].v);
tree[i].v = max (tree[i].v , tree[i].lv);
tree[i].v = max (tree[i].v , tree[i].rv);
if (tree[i<<1|1].lc != tree[i<<1].rc)
tree[i].v = max (tree[i].v , tree[i<<1].rv + tree[i<<1|1].lv);
}
void build (int i , int l , int r)
{
tree[i].l = l , tree[i].r = r;
tree[i].v = tree[i].lv = tree[i].rv = 1;
tree[i].lc = tree[i].rc = 1;
if (l == r)
return ;
int mid = (l + r) >> 1;
build (i<<1, l, mid);
build (i<<1|1, mid + 1, r);
pushup (i);
}
void update (int i , int k)
{
if (tree[i].l == tree[i].r)
{
if (tree[i].lc == 1)
tree[i].lc = tree[i].rc = 0;
else
tree[i].lc = tree[i].rc = 1;
return ;
}
int mid = (tree[i].l + tree[i].r) >> 1;
if (k <= mid)
update (i << 1 , k);
else
update (i << 1 | 1, k);
pushup(i);
}
void dbg (int i)
{
cout << tree[i].l << ' ' << tree[i].r << ' ' << tree[i].v << endl;
cout << tree[i].lc << ' ' << tree[i].rc << ' ' << tree[i].lv << ' ' << tree[i].rv << endl;
if (tree[i].l == tree[i].r)
return ;
dbg (i << 1);
dbg (i << 1 | 1);
}
int main (void)
{
read (n , m);
build (1, 1, n);
while (m --)
{
int x ;
read (x);
update (1, x);
//dbg(1);
//cout << "----------------------------------" << endl;
write (tree[1].v),LF;
}
}
- 三元组计数问题(动态开点权值线段树 或者 离散化+权值线段树),左边统计一下,右边统计一下,先query后insert就行
- 经典例题:P1637
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)
template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
const int N = 1e5 + 5;
const ll R = 1e9;
int n, tot = 0, root;
ll input[N];
int lc[N << 4] , rc[N << 4], val[N << 4];
int l[N] , r[N];
int query (int rt, ll l, ll r, ll tl , ll tr)
{
int ans = 0;
if (tl >= l && tr <= r)
return val[rt];
ll mid = (tl + tr) >> 1;
if (l <= mid) ans += query (lc[rt], l , r, tl , mid);
if (r > mid ) ans += query (rc[rt] ,l , r, mid + 1, tr);
return ans;
}
void insert (int &rt, ll l , ll r ,ll k)
{
if (!rt)
rt = ++ tot;
if (l == r)
{
val[rt] += 1;
return ;
}
ll mid = (l + r) >> 1;
if (k <= mid) insert (lc[rt] , l , mid , k);
else insert (rc[rt], mid + 1, r, k);
val[rt] = val[lc[rt]] + val[rc[rt]];
}
int main (void)
{
read (n);
for (int i = 1 ; i <= n ; i ++)
{
read (input[i]);
l[i] = query (root , 0 , input[i] - 1 , 0, R);
insert (root, 0 , R , input[i]);
}
mem(lc ,0 ) , mem(rc, 0) , mem(val, 0) , root = tot = 0;
for (int i = n ; i >= 1 ; i --)
{
r[i] = query (root , input[i] + 1, R , 0, R);
insert (root, 0 , R , input[i]);
}
ll ans = 0;
for (int i = 1 ; i <= n ; i ++)
ans += l[i] * r[i];
write (ans), LF;
}
- 扫描线
- 经典求面积,注意线段树叶子节点存的实际是线段(区间长度为2)
- 经典例题:P5490
1.非离散化版本
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)
template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
int n ;
const int N = 1e6 + 5;
ll x[N];
struct point{
int l, r, h;
int k;
bool operator < (const point& po) const {
return h < po.h;
}
}line[N];
struct node {
int l , r;
int mark;
ll len;
}tree[N << 4];
void pushup(int i)
{
int l = tree[i].l , r = tree[i].r;
if (tree[i].mark)
tree[i].len = x[r + 1] - x[l];
else
tree[i].len = tree[i<<1].len + tree[i<<1|1].len;
}
void build (int i , int l , int r)
{
tree[i].l = l , tree[i].r = r;
tree[i].len = tree[i].mark = 0;
if (l == r) return ;
int mid = (l + r) >> 1;
build (i << 1 , l , mid);
build (i << 1 | 1, mid + 1, r);
}
void update (int i , ll l, ll r, int k)
{
int tl = tree[i].l , tr = tree[i].r;
if(x[tr + 1] <= l || r <= x[tl])
return;
if (l <= x[tl] && r >= x[tr + 1])
{
tree[i].mark += k;
pushup(i);
return ;
}
update (i << 1 , l , r, k);
update (i << 1 | 1 , l, r, k);
pushup(i);
}
int main (void)
{
read (n);
for (int i = 1 ; i <= n ; i ++)
{
int x1, y1, x2, y2;
read (x1, y1, x2, y2);
x[2 * i - 1] = x1 , x[2 * i] = x2;
line[2 * i - 1] = {x1, x2, y1, 1};
line[2 * i] = {x1, x2, y2, -1};
}
n <<= 1;
sort (line + 1 , line + 1 + n);
sort (x + 1, x + 1 + n);
int tot = unique (x + 1, x + 1 + n) - x - 1;
build (1, 1, tot-1);
ll ans = 0;
for (int i = 1 ; i < n ; i ++)
{
update (1, line[i].l, line[i].r , line[i].k);
//cout << tree[1].len << ' ' << line[i+1].h - line[i].h << endl;
ans += tree[1].len * (line[i+1].h - line[i].h);
}
cout << ans << endl;
}
2.离散化版本
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)
template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
int n ;
const int N = 1e6 + 5;
ll x[N];
struct point{
int l, r, h;
int k;
bool operator < (const point& po) const {
return h < po.h;
}
}line[N];
struct node {
int l , r;
int mark;
ll len;
}tree[N << 4];
void pushup(int i)
{
int l = tree[i].l , r = tree[i].r;
if (tree[i].mark)
tree[i].len = x[r + 1] - x[l];
else
tree[i].len = tree[i<<1].len + tree[i<<1|1].len;
}
void build (int i , int l , int r)
{
tree[i].l = l , tree[i].r = r;
tree[i].len = tree[i].mark = 0;
if (l == r) return ;
int mid = (l + r) >> 1;
build (i << 1 , l , mid);
build (i << 1 | 1, mid + 1, r);
}
void update (int i , ll l, ll r, int k)
{
int tl = tree[i].l , tr = tree[i].r;
if (l <= tl && r >= tr)
{
tree[i].mark += k;
pushup(i);
return ;
}
int mid = (tl + tr) / 2 ;
if (l <= mid) update (i << 1 , l , r, k);
if (r > mid) update (i << 1|1 , l, r, k);
pushup(i);
}
int main (void)
{
read (n);
for (int i = 1 ; i <= n ; i ++)
{
int x1, y1, x2, y2;
read (x1, y1, x2, y2);
x[2 * i - 1] = x1 , x[2 * i] = x2;
line[2 * i - 1] = {x1, x2, y1, 1};
line[2 * i] = {x1, x2, y2, -1};
}
n <<= 1;
sort (line + 1 , line + 1 + n);
sort (x + 1, x + 1 + n);
int tot = unique (x + 1, x + 1 + n) - x - 1;
build (1, 1, tot-1);
ll ans = 0;
for (int i = 1 ; i < n ; i ++)
{
int xl = lower_bound(x+1,x+tot+1,line[i].l) - x;
int xr = lower_bound(x+1,x+tot+1,line[i].r) - x - 1;
update (1, xl, xr , line[i].k);
//cout << tree[1].len << ' ' << line[i+1].h - line[i].h << endl;
ans += tree[1].len * (line[i+1].h - line[i].h);
}
cout << ans << endl;
}
- 经典扫描线求周长(注意sort和cmp)
//#define LOCAL
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)
template<typename T>
void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {read(first);read(args...);}
template<typename T>
void write(T arg) {T x = arg;if(x < 0) {putchar('-'); x =- x;}if(x > 9) {write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {write(arg);if(sizeof...(args) != 0) {putchar(' ');write(args ...);}}
using namespace std;
ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a / gcd(a, b) * b;
}
const int N = 20005;
int n , x[N] , y[N];
struct node {
int l , r;
int mark;
ll len;
}tr[N << 4][5];
struct li
{
int l , r , h, k;
bool operator < (const li& no) const {
return h == no.h ? k > no.k : h < no.h;
}
}linex[N], liney[N];
void pushup(int i, int k)
{
int l = tr[i][k].l , r = tr[i][k].r;
if (k == 0)
{
if (tr[i][k].mark)
tr[i][k].len = x[r + 1] - x[l];
else
tr[i][k].len = tr[i<<1][k].len + tr[i<<1|1][k].len;
}
else
{
if (tr[i][k].mark)
tr[i][k].len = y[r + 1] - y[l];
else
tr[i][k].len = tr[i<<1][k].len + tr[i<<1|1][k].len;
}
}
void build (int k, int i , int l , int r)
{
tr[i][k].l = l , tr[i][k].r = r;
tr[i][k].len = tr[i][k].mark = 0;
if (l == r) return ;
int mid = (l + r) >> 1;
build (k ,i << 1 , l , mid);
build (k ,i << 1 | 1, mid + 1, r);
}
void update (int id, int i , int l, int r, int k)
{
int tl = tr[i][id].l , trr = tr[i][id].r;
if (l <= tl && r >= trr)
{
tr[i][id].mark += k;
pushup(i, id);
return ;
}
int mid = (tl + trr) >> 1 ;
if (l <= mid) update (id, i << 1 , l , r, k);
if (r > mid) update (id, i << 1 | 1 , l, r, k);
pushup(i, id);
}
int main (void)
{
read (n);
for (int i = 1 ; i <= n ; i ++)
{
int x1, y1, x2, y2;
read (x1, y1, x2, y2);
linex[i * 2 - 1] = {x1, x2, y1, 1};
linex[i * 2] = {x1, x2, y2, -1};
liney[i * 2 - 1] = {y1, y2, x1, 1};
liney[i * 2] = {y1, y2, x2, -1};
x[i * 2 - 1] = x1 , x[i * 2] = x2;
y[i * 2 - 1] = y1 , y[i * 2] = y2;
}
n <<= 1;
sort (linex + 1 , linex + 1 + n);
sort (liney + 1, liney + 1 + n);
sort (x + 1, x + 1 + n);
sort (y + 1 , y + 1 + n);
int totx = unique (x + 1 , x + 1 + n) - x - 1;
int toty = unique (y + 1 , y + 1 + n) - y - 1;
build (0, 1, 1, totx - 1);
build (1, 1, 1, toty - 1);
ll ans = 0;
int last = 0;
for (int i = 1 ; i <= n ; i ++)
{
int xl = lower_bound(x + 1, x + 1 + totx, linex[i].l) - x;
int xr = lower_bound(x + 1, x + 1 + totx, linex[i].r) - x - 1;
update(0, 1, xl, xr, linex[i].k);
ans += abs(tr[1][0].len - last) , last = tr[1][0].len;
}
//cout << ans << endl;
last = 0;
for (int i = 1 ; i <= n ; i ++)
{
int yl = lower_bound(y + 1 , y + 1 + toty, liney[i].l) - y;
int yr = lower_bound(y + 1, y + 1 + toty, liney[i].r) - y - 1;
update (1 , 1, yl ,yr, liney[i].k);
ans += abs(tr[1][1].len - last), last = tr[1][1].len;
}
cout << ans << endl;
}