Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解
Posted kirinsb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解相关的知识,希望对你有一定的参考价值。
题意:
\(n\)个草,第\(0\)天种下,高度都为\(0\),每个草每天长高\(a_i\)。现给出\(q\)询问,每次给出第\(b\)天,然后把高于\(d\)的全削成\(d\),每次问你削下来的高度是多少。
思路:
能看出草的顺序和答案无关,那么按\(a_i\)排序,后面的草永远都比前面的高。然后线段树维护区间加,区间重置,区间询问。
代码:
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<bitset>
#include<string>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 5e5 + 5;
const int M = 50 + 5;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const ll MOD = 1000000007;
#define lson (rt << 1)
#define rson (rt << 1 | 1)
int n, m;
ll sum[maxn << 2], sumW[maxn << 2], Mw[maxn << 2], Max[maxn << 2];
ll t[maxn << 2], reset[maxn << 2];
//时间戳,重置
ll a[maxn];
void pushup(int rt)
sum[rt] = sum[lson] + sum[rson];
Max[rt] = Max[rson];
Mw[rt] = Mw[rson];
sumW[rt] = sumW[lson] + sumW[rson];
void pushdown(int rt, int l, int r)
int m = (l + r) >> 1;
if(reset[rt] != -1)
reset[lson] = reset[rt];
reset[rson] = reset[rt];
t[lson] = 0;
t[rson] = 0;
Max[lson] = reset[rt];
Max[rson] = reset[rt];
sum[lson] = 1LL * reset[rt] * (m - l + 1);
sum[rson] = 1LL * reset[rt] * (r - m);
reset[rt] = -1;
if(t[rt])
sum[lson] += t[rt] * sumW[lson];
sum[rson] += t[rt] * sumW[rson];
Max[lson] += t[rt] * Mw[lson];
Max[rson] += t[rt] * Mw[rson];
t[lson] += t[rt];
t[rson] += t[rt];
t[rt] = 0;
void build(int l, int r, int rt)
t[rt] = 0;
reset[rt] = -1;
if(l == r)
sumW[rt] = Mw[rt] = a[l];
sum[rt] = Max[rt] = 0;
return;
int m = (l + r) >> 1;
build(l, m, lson);
build(m + 1, r, rson);
pushup(rt);
void _set(int L, int R, int l, int r, ll v, int rt)
if(L <= l && R >= r)
sum[rt] = 1LL * v * (r - l + 1);
reset[rt] = v;
Max[rt] = v;
t[rt] = 0;
return;
pushdown(rt, l, r);
int m = (l + r) >> 1;
if(L <= m)
_set(L, R, l, m, v, lson);
if(R > m)
_set(L, R, m + 1, r, v, rson);
pushup(rt);
void add(int L, int R, int l, int r, ll v, int rt)
if(L <= l && R >= r)
sum[rt] += sumW[rt] * v;
t[rt] += v;
Max[rt] += Mw[rt] * v;
return;
pushdown(rt, l, r);
int m = (l + r) >> 1;
if(L <= m)
add(L, R, l, m, v, lson);
if(R > m)
add(L, R, m + 1, r, v, rson);
pushup(rt);
ll querysum(int L, int R, int l, int r, int rt)
if(L <= l && R >= r)
return sum[rt];
pushdown(rt, l, r);
int m = (l + r) >> 1;
ll ret = 0;
if(L <= m)
ret += querysum(L, R, l, m, lson);
if(R > m)
ret += querysum(L, R, m + 1, r, rson);
return ret;
int queryMore(int l, int r, ll v, int rt)
if(l == r)
return Max[rt] > v? l : -1;
pushdown(rt, l, r);
int m = (l + r) >> 1;
if(Max[lson] > v)
return queryMore(l, m, v, lson);
else
return queryMore(m + 1, r, v, rson);
int main()
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
sort(a + 1, a + n + 1);
build(1, n, 1);
ll u, v, pre = 0;
while(m--)
scanf("%lld%lld", &u, &v);
add(1, n, 1, n, u - pre, 1);
int pos = queryMore(1, n, v, 1);
if(pos == -1) puts("0");
else
ll ret = querysum(pos, n, 1, n, 1);
ret = ret - 1LL * v * (n - pos + 1);
printf("%lld\n", ret);
_set(pos, n, 1, n, v, 1);
pre = u;
return 0;
以上是关于Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解的主要内容,如果未能解决你的问题,请参考以下文章
Petrozavodsk Summer-2016. Warsaw U Contest, XVI Open Cup Onsite.
Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解
2018-2019 Summer Petrozavodsk Camp, Oleksandr Kulkov Contest 2解题报告
2020 Petrozavodsk Winter Camp, Jagiellonian U Contest 部分题解