离线处理,线段树,区间求和-线段树
Contest (nefu.edu.cn)
Problem:H
Time Limit:2000ms
Memory Limit:165535K
Description
有一个序列包含n个正整数,现在有m次询问,每次询问为:求(L,R)的区间中小于等于K的数的和?
Input
输入包含多组数据。每组数据,第一行为n,表示这个整数序列长为n(1<=n<=1e5)。第二行输入整数序列x1,x2,……,xn(1<=xi<=1e9)。第三行输入m(1<=m<=1e5)。接下来m行,每行输入L,R,K(1<=L<=R<=n,0<=K<=1e9)。
Output
每组数据首先输出“Case #x:”,x从1开始,然后m行输出每次询问的结果,具体格式请参考样例。
Sample Input
6 2 5 3 4 7 6 3 2 5 4 3 6 5 1 4 3
Sample Output
Case #1: 7 7 5
Hint
Source
CJJ
解析:离线处理;
将所有的条件和问题全部读入arr数组中,然后按k值从小到大对数组arr进行排序,最后按照数组arr从1到n+m进行建树,这要就能保证所建的线段树中当前的所有值均小于或等于当前的k值,因此我们只需要通过线段树求出从1到n的所有值的和即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
int n, m;
struct st {
int l, r, k,num;
}arr[4*N];
struct st1 {
int l,r;
LL sum;
}tr[N*4];
typedef struct st2 {
LL v, num;
}st2;
int cmp(const struct st& a, const struct st& b) {
if (a.k == b.k)
return a.num < b.num;
return a.k < b.k;
}
void build(int p, int l, int r) {
tr[p].l = l, tr[p].r = r;
if (l == r) {
return;
}
LL mid = (l + r) / 2;
if (l <= mid)
build(p * 2, l, mid);
if (r > mid)
build(p * 2 + 1, mid + 1, r);
}
void change(int p, int y, int x) {
if (tr[p].l == tr[p].r) {
tr[p].sum = (LL)x;
return;
}
LL mid = (tr[p].l + tr[p].r) / 2;
if (y <= mid)change(p * 2, y, x);
if (y > mid)change(p * 2 + 1, y, x);
tr[p].sum = tr[p * 2].sum + tr[p * 2 + 1].sum;
}
LL ask(int p, int l, int r) {
if (l <= tr[p].l && r >= tr[p].r) {
return tr[p].sum;
}
LL mid = (tr[p].l + tr[p].r) / 2;
LL val = 0;
if (l <= mid)val+=ask(p * 2, l, r);
if (r > mid)val += ask(p * 2 + 1, l, r);
return val;
}
int cmp1(const st2& a, const st2& b) {
return a.num < b.num;
}
int main() {
int cnt = 0;
while (scanf("%d",&n)!=EOF) {
memset(tr, 0, sizeof(tr));
memset(arr, 0, sizeof(arr));
cnt++;
for (int i = 1; i <= n; i++) {
scanf("%d", &arr[i].k);
arr[i].num = i;
}
scanf("%d", &m);
for (int i = n + 1; i <= m + n; i++) {
scanf("%d%d%d", &arr[i].l, &arr[i].r, &arr[i].k);
arr[i].num = i;
}
sort(arr + 1, arr + 1 + n + m, cmp);
build(1, 1, n);
vector<st2>p;
for (int i = 1; i <= n + m; i++) {
if (arr[i].l==0) {
change(1, arr[i].num, arr[i].k);
}
else {
LL t = ask(1, arr[i].l, arr[i].r);
p.push_back({ t,arr[i].num });
}
}
sort(p.begin(), p.end(), cmp1);
printf("Case #%d:\n", cnt);
for (int i = 0; i < m; i++) {
printf("%lld\n", p[i].v);
}
}
return 0;
}