HDU-4348 To the moon
Description
You‘ve been given N integers A [1], A [2],..., A [N]. On these integers, you need to implement the following operations:
1. C l r d: Adding a constant d for every {A i | l <= i <= r}, and increase the time stamp by 1, this is the only operation that will cause the time stamp increase.
2. Q l r: Querying the current sum of {A i | l <= i <= r}.
3. H l r t: Querying a history sum of {A i | l <= i <= r} in time t.
4. B t: Back to time t. And once you decide return to a past, you can never be access to a forward edition anymore.
.. N, M ≤ 10 5, |A [i]| ≤ 10 9, 1 ≤ l ≤ r ≤ N, |d| ≤ 10 4 .. the system start from time 0, and the first modification is in time 1, t ≥ 0, and won't introduce you to a future state.
Input
n m
A 1 A 2 ... A n
... (here following the m operations. )
Output
... (for each query, simply print the result. )
Sample Input
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
2 4
0 0
C 1 1 1
C 2 2 -1
Q 1 2
H 1 2 1
Sample Output
4
55
9
15
0
1
题解
主席树+标记永久化,如果添加标记后每次都pushdown,对于主席树来说,每次pushdown都要新建一条链上的节点,如果pushdown我们的空间复杂度是不够的,所以我们要标记永久化,在查询的时候我们记录一下从根节点开始的标记是多少,每次统计答案时加上标记的贡献即可,回退版本时可以直接修改cnt为t+1版本的cnt,因为回退版本后不能返回,可以减少空间
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, q;
const int N = 1e5 + 10;
ll a[N];
int L[N * 30], R[N * 30], T[N];
ll sum[N * 30];
ll addv[N * 30];
int cnt;
void pushup(int rt, int l, int r) {
sum[rt] = sum[L[rt]] + sum[R[rt]] + addv[rt] * (r - l + 1);
}
int build(int l, int r) {
int rt = ++cnt;
if (l == r) {
sum[rt] = a[l];
return rt;
}
int mid = (l + r) >> 1;
if (l < r) {
L[rt] = build(l, mid);
R[rt] = build(mid + 1, r);
}
pushup(rt, l, r);
return rt;
}
int update(int pre, int l, int r, int ql, int qr, ll v) {
int rt = ++cnt;
int mid = (l + r) >> 1;
L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre], addv[rt] = addv[pre];
if (ql <= l && r <= qr) {
sum[rt] += (ll)(r - l + 1) * v;
addv[rt] += v;
return rt;
}
if (ql <= mid) L[rt] = update(L[pre], l, mid, ql, qr, v);
if (qr > mid) R[rt] = update(R[pre], mid + 1, r, ql, qr, v);
pushup(rt, l, r);
return rt;
}
ll query(int rt, int l, int r, int ql, int qr, ll tot) {
if (ql <= l && r <= qr) {
return sum[rt] + tot * (r - l + 1);
}
tot += addv[rt];
int mid = (l + r) >> 1;
ll ans = 0;
//pushdown(rt, l, r, L[rt], R[rt]);
if (ql <= mid) ans += query(L[rt], l, mid, ql, qr, tot);
if (qr > mid) ans += query(R[rt], mid + 1, r, ql ,qr, tot);
return ans;
}
int main() {
while (~scanf("%d%d", &n, &q)) {
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
cnt = 0;
memset(sum, 0, sizeof(sum));
memset(addv, 0, sizeof(addv));
T[0] = build(1, n);
int now = 0;
for (int i = 1; i <= q; i++) {
char ch[2];
int l, r; ll v;
int t;
scanf("%s", ch);
if (ch[0] == 'Q') {
scanf("%d%d", &l, &r);
printf("%lld
", query(T[now], 1, n, l, r, 0));
}
if (ch[0] == 'C') {
scanf("%d%d%lld", &l, &r, &v);
now++;
T[now] = update(T[now - 1], 1, n, l, r, v);
}
if (ch[0] == 'H') {
scanf("%d%d%d", &l, &r, &t);
printf("%lld
", query(T[t], 1, n, l, r, 0));
}
if (ch[0] == 'B') {
scanf("%d", &t);
now = t;
cnt = T[now + 1];
}
}
}
return 0;
}
HDU-6278 Just (h)-index
Description
The (h)-index of an author is the largest (h) where he has at least (h) papers with citations not less than (h).
Bobo has published (n) papers with citations (a_1, a_2, dots, a_n) respectively.
One day, he raises (q) questions. The (i)-th question is described by two integers (l_i) and (r_i), asking the (h)-index of Bobo if has only published papers with citations (a_{l_i}, a_{l_i + 1}, dots, a_{r_i}).
Input
The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains two integers (n) and (q).
The second line contains (n) integers (a_1, a_2, dots, a_n).
The (i)-th of last (q) lines contains two integers (l_i) and (r_i).
Output
For each question, print an integer which denotes the answer.
## Constraint
* (1 leq n, q leq 10^5)
* (1 leq a_i leq n)
* (1 leq l_i leq r_i leq n)
* The sum of (n) does not exceed (250,000).
* The sum of (q) does not exceed (250,000).
Sample Input
5 3
1 5 3 2 1
1 3
2 4
1 5
5 1
1 2 3 4 5
1 5
Sample Output
2
2
2
3
题解
二分答案+主席树,水题
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m;
const int N = 1e5 + 10;
int a[N];
int L[N * 20], R[N * 20], T[N];
int sum[N * 20];
int b[N];
int cnt;
int build(int l, int r) {
int rt = ++cnt;
sum[rt] = 0;
int mid = (l + r) >> 1;
if (l < r) {
L[rt] = build(l, mid);
R[rt] = build(mid + 1, r);
}
return rt;
}
int update(int pre, int l, int r, int x) {
int rt = ++cnt;
int mid = (l + r) >> 1;
L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + 1;
if (l < r) {
if (x <= mid) L[rt] = update(L[pre], l, mid, x);
else R[rt] = update(R[pre], mid + 1, r, x);
}
return rt;
}
int query(int u, int v, int l, int r, int k) {
if (l >= r) return l;
int mid = (l + r) >> 1;
int x = sum[L[v]] - sum[L[u]];
if (x >= k) return query(L[u], L[v], l, mid, k);
else return query(R[u], R[v], mid + 1, r, k - x);
}
int main() {
while (~scanf("%d%d", &n, &m)) {
cnt = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(b + 1, b + n + 1);
int cnt1 = unique(b + 1, b + n + 1) - b - 1;
T[0] = build(1, cnt1);
for (int i = 1; i <= n; i++) {
a[i] = lower_bound(b + 1, b + cnt1 + 1, a[i]) - b;
T[i] = update(T[i - 1], 1, cnt1, a[i]);
}
while (m--) {
int x, y;
scanf("%d%d", &x, &y);
int l = 1, r = y - x + 1;
int ans = 0;
while (l <= r) {
int mid = (l + r) >> 1;
if (b[query(T[x - 1], T[y], 1, cnt1, y - x + 2 - mid)] >= mid) {
ans = max(ans, mid);
l = mid + 1;
}
else r = mid - 1;
}
printf("%d
", ans);
}
}
return 0;
}
HDU-5919 Sequence II
Description
Mr. Frog has an integer sequence of length n, which can be denoted as (a_1,a_2,cdots ,a_n) There are m queries.
In the i-th query, you are given two integers (l_i) and (r_i). Consider the subsequence $a_{l_i},a_{l_{i+1}},a_{l_{i+2}},cdots ,a_{r_i} $.
We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as (p_{1}^{(i)},p_{2}^{(i)},cdots, p_{k_i}^{(i)}) (in ascending order, i.e.,(p_{1}^{(i)}<p_{2}^{(i)}<cdots <p_{k_i}^{(i)})).
Note that (k_i) is the number of different integers in this subsequence. You should output (p_{left lceil frac{k_i}{2} ight ceil}^{(i)})for the i-th query.
Input
In the first line of input, there is an integer T ((Tleq 2)) denoting the number of test cases.
Each test case starts with two integers n ((n leq 2 imes 10^5)) and m ((mleq 2 imes 10^5)). There are n integers in the next line, which indicate the integers in the sequence(i.e., (a_1,a_2,cdots ,a_n, 0leq a_i leq 2 imes 10^5)).
There are two integers (l_i) and (r_i) in the following m lines.
However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to (l_i^`,r_i^`(1leq l_i^` leq n,1leq r_i^` leq n )). As a result, the problem became more exciting.
We can denote the answers as (ans_1, ans_2,cdots ,ans_m). Note that for each test case (ans_0 = 0).
You can get the correct input (l_i,r_i) from what you read (we denote them as (l_i^`,r_i^`))by the following formula:
Output
You should output one single line for each test case.
For each test case, output one line “Case #x: (p_1,p_2,cdots ,p_m)”, where x is the case number (starting from 1) and (p_1,p_2,cdots ,p_m) is the answer.
Sample Input
2
5 2
3 3 1 5 4
2 2
4 4
5 2
2 5 2 1 2
2 3
2 4
Sample Output
Case #1: 3 3
Case #2: 3 1
Hint
题解
将主席树倒着插入,可以统计区间[l,r]的数的种类,具体方法是:
维护一个pos数组,pos[a[i]]记录a[i]出现的最后的位置(倒着插入,即最靠左的位置),主席树则维护每一个位置有没有数,而不是以数的值为主席树下标。这样我们插入一个数时,如果pos[a[i]]==0,z,则直接在i位置+1,否则先将pos[a[i]]位置-1,再将i位置+1,这样区间端点(l)对应的主席树就维护了l之后的数的种数,我们只要查询[l,r]内有多少数就可以了,查询完之后再这颗树上求第((sum + 1) / 2)大的下标是多少就可以
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m;
const int N = 2e5 + 100;
int a[N];
int L[N * 40], R[N * 40], T[N];
int sum[N * 40];
int cnt;
int getnum() {
int ans = 0; char c;
while (!isdigit(c = getchar()));
ans = c - '0';
while (isdigit(c = getchar())) ans = ans * 10 + c - '0';
return ans;
}
int build(int l, int r) {
int rt = ++cnt;
sum[rt] = 0;
int mid = (l + r) >> 1;
if (l < r) {
L[rt] = build(l, mid);
R[rt] = build(mid + 1, r);
}
return rt;
}
int update(int pre, int l, int r, int x, int v) {
int rt = ++cnt;
int mid = (l + r) >> 1;
L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + v;
if (l < r) {
if (x <= mid) L[rt] = update(L[pre], l, mid, x, v);
else R[rt] = update(R[pre], mid + 1, r, x, v);
}
return rt;
}
int querysum(int rt, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return sum[rt];
}
int mid = (l + r) >> 1;
int ans = 0;
if (ql <= mid) ans += querysum(L[rt], l, mid, ql, qr);
if (qr > mid) ans += querysum(R[rt], mid + 1, r, ql, qr);
return ans;
}
int queryk(int v, int l, int r, int k) {
if (l >= r) return l;
int mid = (l + r) >> 1;
int x = sum[L[v]];
if (x >= k) return queryk(L[v], l, mid, k);
else return queryk(R[v], mid + 1, r, k - x);
}
int pos[N];
int main() {
int t;
t = getnum();
int cse = 0;
//freopen("ans.txt", "w", stdout);
while (t--) {
n = getnum(), m = getnum();
cnt = 0;
for (int i = 1; i <= n; i++) {
a[i] = getnum();
}
T[n + 1] = build(1, n);
memset(pos, 0, sizeof(pos));
for (int i = n; i >= 1; i--) {
if (!pos[a[i]]) {
T[i] = update(T[i + 1], 1, n, i, 1);
pos[a[i]] = i;
}
else {
T[i] = update(T[i + 1], 1, n, i, 1);
T[i] = update(T[i], 1, n, pos[a[i]], -1);
pos[a[i]] = i;
}
}
int ans = 0;
cse++;
printf("Case #%d:", cse);
while (m--) {
int l, r;
l = getnum(), r = getnum();
l = (l + ans) % n + 1;
r = (r + ans) % n + 1;
if (l > r) swap(l, r);
int num = querysum(T[l], 1, n, l, r);
printf(" %d", ans = queryk(T[l], 1, n, (num + 1) / 2));
}
printf("
");
}
return 0;
}