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;
}

原文地址:https://www.cnblogs.com/KirinSB/p/11618662.html

时间: 2024-07-30 14:01:08

Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解的相关文章

2015-2016 Petrozavodsk Winter Training Camp, Makoto rng_58 Soejima Сontest 4题解

传送门 被\(jz\)姐姐带着飞--代码的话直接在上面找吧 \(A\) 发现这样的数不会很多,直接把所有的都打表打出来就行了 \(B\) 转换成切比雪夫距离后,每个点分别向\(x,y\)坐标最大最小的点连边,跑个最大生成树就行了 \(C\) 最终的柿子一定行如\(s\pm t=2a_{i_1}-2a_{i_2}+...\),那么直接\(bfs\)出所有可能的结果,然后根据奇偶性判断一下就行了 原文地址:https://www.cnblogs.com/yuanquming/p/11715366.h

2015 UESTC Winter Training #7【2010-2011 Petrozavodsk Winter Training Camp, Saratov State U Contest】

2015 UESTC Winter Training #7 2010-2011 Petrozavodsk Winter Training Camp, Saratov State U Contest 据说这套题写出3题就是金牌水平了... Problem D. Group Stage 足球比赛,现在有n(2<= n <=100)支球队.要从中选拔m(1<= m <=n-1)支球队,每支球队互相比赛一场,即比赛n*(n-1)/2场,胜者得3分,平局各得1分.最后从大到小列出排名,如果有

Petrozavodsk Summer Training Camp 2017

Petrozavodsk Summer Training Camp 2017 Problem A. Connectivity 题目描述:有\(n\)个点,现不断地加边.每条边有一种颜色,如果一个点对\((a, b)\),满足\(a=b\)或对于每一种颜色的子图(图中只有该种颜色的边),\(a, b\)总是连通,则该点对称为好连通.求出每加一条边,好连通的点对数. solution 每个子图用并查集维护连通块,并且用\(vector\)记录每个连通块的点,便于之后进行答案的统计,合并时启发式合并即

BZOJ 3211 花神游历各国 线段树题解

BZOJ 3211 花神游历各国 线段树题解 3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2551  Solved: 946[Submit][Status][Discuss] Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4 Sample Output 101

线段树&#183;题解报告

线段树·题解报告 参考资料 ·课件 线段树 --刘汝佳 统计的力量,线段树全接触 --张昆玮 ·Blog [完全版]线段树 从普通线段树到zkw线段树 [总结][数据结构]ZKW线段树详解 选题目录 · Hdu1166 敌兵布阵(单点更新,区间求和) · Hdu1754 I Hate It(单点更新,RMQ) · Hdu3308 LCIS(单点更新,区间并) · Poj3468 A Simple Problem with Integers(区间加减,区间求和) · Poj2777 Count C

POJ 2528 Mayor&#39;s posters 离散化和线段树题解

本题就是要往墙上贴海报,问最后有多少可见的海报. 其实本题的难点并不是线段树,而是离散化. 因为数据很大,直接按原始数据计算那么就会爆内存和时间的. 故此需要把数据离散化. 比如有海报1 6   7 9   20 100  5 1000的原始数据,直接计算需要1-1000的内存,离散化之后只需要8内存,因为只有4组数据8个数. 本题更进一步高级一点的离散化就是需要把不相邻的两个数据插入一个数值,表示有空白的地方,不是所有海报都覆盖到的. 比如上面的数据要离散为:1 2  5 6  7 8 9 1

POJ 2528 Mayor&amp;#39;s posters 离散化和线段树题解

本题就是要往墙上贴海报,问最后有多少可见的海报. 事实上本题的难点并非线段树,而是离散化. 由于数据非常大,直接按原始数据计算那么就会爆内存和时间的. 故此须要把数据离散化. 比方有海报1 6   7 9   20 100  5 1000的原始数据.直接计算须要1-1000的内存,离散化之后仅仅须要8内存,由于仅仅有4组数据8个数. 本题更进一步高级一点的离散化就是须要把不相邻的两个数据插入一个数值.表示有空白的地方,不是全部海报都覆盖到的. 比方上面的数据要离散为:1 2  5 6  7 8

【博弈论】【SG函数】【线段树】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem H. Cups and Beans

一开始有n个杯子,每个杯子里有一些豆子,两个人轮流操作,每次只能将一个豆子移动到其所在杯子之前的某个杯子里,不过可以移动到的范围只有一段区间.问你是否先手必胜. 一个杯子里的豆子全都等价的,因为sg函数是异或起来的值,所以一个杯子里如果有偶数个豆子,就没有意义. 用sg(i)表示i杯子中的豆子的sg值,sg(i)就是其所能移动到的那段杯子的区间的sg值的mex(未出现的最小非负整数).可以用线段树去做.是经典问题. 由于每次看似是后缀询问,实则是全局询问,故而主席树完全是多余的. 回顾一下区间m

【线段树】【扫描线】Petrozavodsk Winter Training Camp 2018 Day 5: Grand Prix of Korea, Sunday, February 4, 2018 Problem A. Donut

题意:平面上n个点,每个点带有一个或正或负的权值,让你在平面上放一个内边长为2l,外边长为2r的正方形框,问你最大能圈出来的权值和是多少? 容易推出,能框到每个点的 框中心 的范围也是一个以该点为中心的相同大小的框. 于是,把每个点的框拆成4条线.从下往上扫过去,最下面的线,给[R,R]区间加上该点的权值,然后上面再给[L,L]减去,然后上面再给[L,L]加上,然后再往上在给[R,R]减去即可.每次扫完一行,就用线段树的全局最大值尝试更新答案. 两个坑点:首先,由于线段树里存储的是离散后的点,所