2020浙江省赛E Easy DP Problem 主席树

传送门:https://zoj.pintia.cn/problem-sets/91827364500/problems/1319565562453364740

题意

根据题目dp的方向,直接判断出最后答案为1到(r-l+1)的平方和加上l到r区间前k大的值。

思路

平方和直接可以公式$\frac{n(n+1)(2n+1)}{6}$。 区间前k大可以主席树套一下。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
##include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pdd;

##define INF 0x3f3f3f3f
##define lowbit(x) x & (-x)
##define mem(a, b) memset(a , b , sizeof(a))
##define FOR(i, x, n) for(int i = x;i <= n; i++)

// const ll mod = 998244353;
// const ll mod = 1e9 + 7;
// const double eps = 1e-6;
// const double PI = acos(-1);
// const double R = 0.57721566490153286060651209;

const int N = 1e6 + 10;
int a[N];
vector<int> v;
int cnt, root[N];

struct Node {
int l, r;
ll sum;
int num;
int val;
}hjt[N * 40];

int getid(int x) { return lower_bound(v.begin(), v.end(), x) - v.begin() + 1; }

void insert(int pre, int &now, int l, int r, int p, int val) {
now = ++cnt;
hjt[now] = hjt[pre];
hjt[now].num++; hjt[now].sum += val;
if(l == r) {
hjt[now].val = val;
return ;
}
int m = (l + r) >> 1;
if(p <= m) insert(hjt[pre].l, hjt[now].l, l, m, p, val);
else insert(hjt[pre].r, hjt[now].r, m + 1, r, p, val);
}

ll query(int L, int R, int l, int r, int k) {
if(l == r) return hjt[R].val * k;
int m = (l + r) >> 1;
int tmp = hjt[hjt[R].r] .num - hjt[hjt[L].r].num;
if(k <= tmp) return query(hjt[L].r, hjt[R].r, m + 1, r, k);
else return hjt[hjt[R].r].sum - hjt[hjt[L].r].sum + query(hjt[L].l, hjt[R].l, l, m, k - tmp);
}

void init(int n) {
v.clear();
cnt = 0;
for(int i = 1;i <= n; i++) {
scanf("%d",&a[i]);
v.push_back(a[i]); root[i] = 0;
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
}

void solve()
{
int _;
scanf("%d",&_);
while(_--) {
int n;
scanf("%d",&n);
init(n);
for(int i = 1;i <= n; i++) {
int t = getid(a[i]);
insert(root[i - 1], root[i], 1, n, t, a[i]);
}
int q;
scanf("%d",&q);
while(q--) {
int l, r, k;
scanf("%d%d%d",&l,&r,&k);
int t = r - l + 1;
ll ans = query(root[l - 1], root[r], 1, n, k);
printf("%lld\n",1ll * t * (t + 1) * (2 * t + 1) / 6 + ans);
}
}
}

signed main() {
ios_base::sync_with_stdio(false);
//cin.tie(nullptr);
//cout.tie(nullptr);
##ifdef FZT_ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
##else
solve();
##endif
return 0;
}

要是当时会写主席树就能有牌子了,可惜了。

这篇博客好水

本文作者:jujimeizuo
本文地址https://blog.jujimeizuo.cn/2020/11/12/2020-zhejiang-shengsai-e/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!