影子的宽度
题目描述
桌子上零散地放着若干个盒子,盒子都平行于墙。桌子的后方是一堵墙。如图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?
输入
第1行:3个整数L,R,N。-100000 <=L<=R<= 100000,表示墙所在的区间;1<=N<=100000,表示盒子的个数
接下来N行,每行2个整数BL, BR,-100000 <=BL<=BR<= 100000,表示一个盒子的左、右端点(左闭右开)
输出
第1行:1个整数W,表示影子的总宽度。
样例输入
Sample Input 1
扫描二维码关注公众号,回复:
12585764 查看本文章
0 7 2
1 2
4 5
Sample Output 1
2
Sample Input 2
-10 10 2
-5 2
-2 2
Sample Output 2
7
Sample Input 3
-10 10 3
-7 0
-4 9
-4 2
Sample Output 3
16
Sample Input 4
-100 100 3
-7 2
5 9
2 5
Sample Output 4
16
Sample Input 5
-50 50 4
-2 4
0 6
9 10
-5 30
Sample Output 5
35
大致就是一道考察懒标记的题,比较简单
因为下标是可能为负,需要加一个偏移量
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;
typedef long long ll;
ll a[N];
struct Node {
int l, r;
ll sum, maxv, lazy;
void updade() {
sum = r - l + 1;
lazy = 1;
}
} tree[N * 4];
void build(int p, int l, int r)
{
tree[p].l = l, tree[p].r = r;
tree[p].sum = tree[p].lazy = 0;
if (l == r) {
tree[p].sum = tree[p].maxv = a[l];
return;
}
int mid = l + r >> 1;
build(p << 1, l , mid);
build(p << 1 | 1, mid + 1, r);
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
tree[p].maxv = max(tree[p << 1].maxv, tree[p << 1 | 1].maxv);
}
void spread(int p)
{
int lazy_val = tree[p].lazy;
if (lazy_val) {
tree[p << 1].updade();
tree[p << 1 | 1].updade();
tree[p].lazy = 0;
}
}
void update(int p, int l, int r)
{
if (l <= tree[p].l && tree[p].r <= r) {
tree[p].updade();
} else {
spread(p);
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid)
update(p << 1, l, r);
if (r > mid)
update(p << 1 | 1, l, r);
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
//tree[p].maxv = max(tree[p << 1].maxv , tree[p << 1 | 1].maxv);
}
}
ll query(int p, int l, int r)
{
if (l <= tree[p].l && tree[p].r <= r)
return tree[p].sum;
spread(p);
ll ans = 0;
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid)
ans = ans + query(p << 1, l, r);
if (r > mid)
ans = ans + query(p << 1 | 1, l, r);
return ans;
}
int main()
{
int L, R, n, q, l, r, d;
scanf("%d%d%d", &L, &R, &q);
d = -L + 1; // 偏移量
build(1, L + d, R + d);
while (q--) {
scanf("%d%d", &l, &r);
update(1, l + d, r - 1 + d);
}
printf("%lld\n", query(1, L + d, R + d));
return 0;
}
区间平方和问题:
给你一个长度为N的序列,之后有M次操作,操作包括两类:
A L R 为给区间[L,R]的所有数都加上一个A的值
S L R 为求区间[L,R]的所有数的平方的和
如果一个区间内的所有数字,都加上A,那么psum = 2 * sum * A + (r - l + 1) * A
注意要先更新psum,再更新sum
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;
typedef long long ll;
ll a[N];
struct Node {
int l, r;
ll sum, psum, maxv, lazy;
void updade(ll x) {
psum += (r - l + 1) * x * x + 2 * x * sum;
sum += (r - l + 1) * x;
lazy += x;
}
} tree[N * 4];
void push_up(int p)
{
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
tree[p].psum = tree[p << 1].psum + tree[p << 1 | 1].psum;
}
void build(int p, int l, int r)
{
tree[p].l = l, tree[p].r = r;
tree[p].psum = tree[p].sum = tree[p].lazy = 0;
if (l == r) {
tree[p].sum = tree[p].maxv = a[l];
tree[p].psum = a[l] * a[l];
return;
}
int mid = l + r >> 1;
build(p << 1, l , mid);
build(p << 1 | 1, mid + 1, r);
push_up(p);
//tree[p].maxv = max(tree[p << 1].maxv, tree[p << 1 | 1].maxv);
}
void spread(int p)
{
int lazy_val = tree[p].lazy;
if (lazy_val) {
tree[p << 1].updade(lazy_val);
tree[p << 1 | 1].updade(lazy_val);
tree[p].lazy = 0;
}
}
void update(int p, int l, int r, int val)
{
if (l <= tree[p].l && tree[p].r <= r) {
tree[p].updade(val);
} else {
spread(p);
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid)
update(p << 1, l, r, val);
if (r > mid)
update(p << 1 | 1, l, r, val);
push_up(p);
}
}
ll query(int p, int l, int r)
{
if (l <= tree[p].l && tree[p].r <= r)
return tree[p].psum;
spread(p);
ll ans = 0;
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid)
ans = ans + query(p << 1, l, r);
if (r > mid)
ans = ans + query(p << 1 | 1, l, r);
return ans;
}
int main()
{
int n, q, l, r, val, opt;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%lld", a + i);
build(1, 1, n);
scanf("%d", &q);
while (q--) {
scanf("%d", &opt);
if (opt == 2) {
scanf("%d %d", &l, &r);
printf("%lld\n", query(1, l, r));
} else {
scanf("%d %d %d", &l, &r, &val);
update(1, l, r, val);
}
}
return 0;
}
区间开根号问题
还有bug没有调出来QAQ
stars
题目传送门:poj 2352
需要注意线段树的大小,还有因为 x 坐标是从 0 开始的,需要对x++
#include <cstdio>
#include <algorithm>
using namespace std;
const int MOD = 1e9 + 7;
const int N = 3e4 + 10;
typedef long long ll;
ll a[N];
ll res[N];
struct Node {
int l, r;
ll sum, maxv, lazy;
void updade(ll x) {
sum += (r - l + 1) * x;
maxv += x;
lazy += x;
}
} tree[N * 4];
void build(int p, int l, int r)
{
tree[p].l = l, tree[p].r = r;
tree[p].sum = tree[p].lazy = 0;
if (l == r) {
tree[p].sum = tree[p].maxv = a[l];
return;
}
int mid = l + r >> 1;
build(p << 1, l , mid);
build(p << 1 | 1, mid + 1, r);
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
tree[p].maxv = max(tree[p << 1].maxv, tree[p << 1 | 1].maxv);
}
void spread(int p)
{
int lazy_val = tree[p].lazy;
if (lazy_val) {
tree[p << 1].updade(lazy_val);
tree[p << 1 | 1].updade(lazy_val);
tree[p].lazy = 0;
}
}
void update(int p, int x, int val)
{
if (tree[p].l == tree[p].r) {
tree[p].updade(val);
} else {
//spread(p);
int mid = tree[p].l + tree[p].r >> 1;
if (x <= mid)
update(p << 1, x, val);
if (x > mid)
update(p << 1 | 1, x, val);
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
tree[p].maxv = max(tree[p << 1].maxv , tree[p << 1 | 1].maxv);
}
}
ll query(int p, int l, int r)
{
if (l <= tree[p].l && tree[p].r <= r)
return tree[p].sum;
//spread(p);
ll ans = 0;
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid)
ans = ans + query(p << 1, l, r);
if (r > mid)
ans = ans + query(p << 1 | 1, l, r);
return ans;
}
int main()
{
int n, q, x, y, val, opt;
scanf("%d", &n);
build(1, 1, 32005);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &x, &y);
x++;
int k = query(1, 1, x);
res[k]++;
update(1, x, 1);
}
for (int i = 0; i <= n - 1; i++) {
printf("%lld\n", res[i]);
}
return 0;
}
逆序对
题目传送门:逆序对
需要进行离散化
离散化之后从右向左依次遍历,假设当前数是 x ,查询有多少之前出现过的(即在 x 右边的)数字
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
const int N = 5e5 + 10;
typedef long long ll;
ll a[N], b[N];
int n, m;
struct Node {
int l, r;
ll sum, maxv, lazy;
void updade(ll x) {
sum += (r - l + 1) * x;
maxv += x;
lazy += x;
}
} tree[N * 4];
void push_up(int p)
{
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
tree[p].maxv = max(tree[p << 1].maxv, tree[p << 1 | 1].maxv);
}
void build(int p, int l, int r)
{
tree[p].l = l, tree[p].r = r;
tree[p].sum = tree[p].lazy = 0;
if (l == r) {
tree[p].sum = tree[p].maxv = a[l];
return;
}
int mid = l + r >> 1;
build(p << 1, l , mid);
build(p << 1 | 1, mid + 1, r);
push_up(p);
}
void spread(int p)
{
int lazy_val = tree[p].lazy;
if (lazy_val) {
tree[p << 1].updade(lazy_val);
tree[p << 1 | 1].updade(lazy_val);
tree[p].lazy = 0;
}
}
void update(int p, int l, int r, int val)
{
if (l <= tree[p].l && tree[p].r <= r) {
tree[p].updade(val);
} else {
spread(p);
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid)
update(p << 1, l, r, val);
if (r > mid)
update(p << 1 | 1, l, r, val);
push_up(p);
}
}
ll query(int p, int l, int r)
{
if (l <= tree[p].l && tree[p].r <= r)
return tree[p].sum;
spread(p);
ll ans = 0;
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid)
ans = ans + query(p << 1, l, r);
if (r > mid)
ans = ans + query(p << 1 | 1, l, r);
return ans;
}
void discrete()
{
sort(b + 1, b + n + 1);
for (int i = 1; i <= n; i++) {
if (i == 1 || b[i] != b[i - 1])
b[++m] = b[i];
}
}
int main()
{
int q, l, r, val, opt;
scanf("%d", &n);
build(1, 1, n);
for (int i = 1; i <= n; ++i) {
scanf("%lld", a + i);
b[i] = a[i];
}
ll idx, res = 0;
discrete();
for (int i = n; i >= 1; i--) {
idx = lower_bound(b + 1, b + m + 1, a[i]) - b;
res += query(1, 1, idx - 1);
update(1, idx, idx, 1);
}
printf("%lld\n", res);
return 0;
}