[CSP-S模拟测试]:Weed(线段树)
题目描述
$duyege$的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹。
为了查出真相,$duyege$准备修好电脑之后再进行一次金坷垃的模拟实验。
电脑上面有若干层金坷垃,每次只能在上面撒上一层高度为$v_i$的金坷垃,或者除掉最新$v_i$层(不是量)撒的金坷垃。如果上面只留有不足$v_i$层金坷垃,那么就相当于电脑上面没有金坷垃了。
$duyege$非常严谨,一开始先给你$m$个上述操作要你依次完成。然后又对实验步骤进行了$q$次更改,每次更改都会改变其中一个操作为另外一个操作。每次修改之后都会询问最终金坷垃的量有多少。
输入格式
输入第一行为两个正整数$m$、$q$,接下来$m$行每行$2$个整数$k$、$v_i$。$k$为$0$时撒金坷垃,为$1$时除金坷垃。接下来$q$行每行$3$个整数$c_i$、$k$、$v_i$,$c_i$代表被更改的操作是第$c_i$个,后面$2$个数描述更改为这样的操作。
输出格式
输出$q$行代表每次金坷垃的量为多少。
样例
样例输入
10 5
0 10
1 5
0 13
0 18
0 2
1 1
0 8
0 9
1 3
0 7
9 0 3
10 1 7
6 0 8
10 0 5
8 1 2
样例输出
58
0
0
66
41
数据范围与提示
对于$30%$的数据$m\leqslant 1,000,q\leqslant 1,000$。
对于另外$20%$的数据,每次$k=1$时都会将金坷垃清空。
对于$100%$的数据,$m\leqslant 2\times {10}^5,q\leqslant 2\times {10}^5,v_i\leqslant {10}^4$。
题解
首先,来解释一下题意,在更改操作之后就不改回来啦。
$30%$算法:
暴力修改,每次都暴力扫一遍统计答案。
时间复杂度:$\Theta(m\times q)$。
期望得分:$30$分。
实际得分:$30$分。
$100%$算法:
利用线段树维护以下四个值:
$\alpha.$区间内加数总和$sum$。
$\beta.$当前区间向前删除数字的数量$del$。
$gamma.$当前区间内“净”加的元素数$add$。
$delta.$当前区间被右兄弟删除后的总和$fla$(只对左儿子维护这个信息即可)。
每次询问就是输出$sum[1]$。
之后就是代码实现的问题了,主要是$pushup$函数比较难搞。
时间复杂度:$\Theta(N\log N+Q\log^2N)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
$30%$算法:
#include<bits/stdc++.h>
using namespace std;
int m,q;
pair<bool,int> e[200001];
int sta[200001],top;
int ans;
int main()
{
scanf("%d%d",&m,&q);
for(int i=1;i<=m;i++)
scanf("%d%d",&e[i].first,&e[i].second);
while(q--)
{
ans=0;
top=0;
int c,k,v;
scanf("%d%d%d",&c,&k,&v);
e[c]=make_pair(k,v);
for(int i=1;i<=m;i++)
if(e[i].first==1)for(int j=1;j<=e[i].second;j++)if(top)top--;else break;
else sta[++top]=e[i].second;
for(int i=1;i<=top;i++)ans+=sta[i];
printf("%d\n",ans);
}
return 0;
}
$100%$算法:
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
int m,q;
int c,k,v;
pair<bool,int> e[200001];
int tradd[1000000],trdel[1000000],trfla[1000000],trsum[1000000];
int ask(int x,int w)
{
if(w<tradd[R(x)])return trfla[L(x)]+ask(R(x),w);
if(w==tradd[R(x)])return trfla[L(x)];
if(w>tradd[R(x)])return ask(L(x),w-tradd[R(x)]+trdel[R(x)]);
}
void pushup(int x)
{
if(tradd[L(x)]<=trdel[R(x)])
{
trfla[L(x)]=0;
tradd[x]=tradd[R(x)];
trdel[x]=trdel[L(x)]+trdel[R(x)]-tradd[L(x)];
trsum[x]=trsum[R(x)];
}
else
{
if(trdel[R(x)])trfla[L(x)]=ask(L(x),trdel[R(x)]);
else trfla[L(x)]=trsum[L(x)];
tradd[x]=tradd[L(x)]+tradd[R(x)]-trdel[R(x)];
trdel[x]=trdel[L(x)];
trsum[x]=trfla[L(x)]+trsum[R(x)];
}
}
void build(int x,int l,int r)
{
if(l==r)
{
if(e[l].first)trdel[x]=e[l].second;
else
{
tradd[x]=1;
trsum[x]=e[l].second;
trfla[x]=e[l].second;
}
return;
}
int mid=(l+r)>>1;
build(L(x),l,mid);
build(R(x),mid+1,r);
pushup(x);
}
void clear(int x){tradd[x]=trdel[x]=trsum[x]=trfla[x]=0;}
void change(int x,int l,int r,int w)
{
if(l==r)
{
clear(x);
if(e[l].first)trdel[x]=e[l].second;
else
{
tradd[x]=1;
trsum[x]=e[l].second;
trfla[x]=e[l].second;
}
return;
}
int mid=(l+r)>>1;
if(w<=mid)change(L(x),l,mid,w);
else change(R(x),mid+1,r,w);
pushup(x);
}
int main()
{
scanf("%d%d",&m,&q);
for(int i=1;i<=m;i++)
scanf("%d%d",&e[i].first,&e[i].second);
build(1,1,m);
while(q--)
{
scanf("%d%d%d",&c,&k,&v);
e[c]=make_pair(k,v);
change(1,1,m,c);
printf("%d\n",trsum[1]);
}
return 0;
}
rp++
[CSP-S模拟测试]:Weed(线段树)的更多相关文章
- 【bzoj3638】Cf172 k-Maximum Subsequence Sum 模拟费用流+线段树区间合并
题目描述 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少. 输入 The first line contains inte ...
- 【BZOJ 2957】楼房重建&&Codechef COT5 Count on a Treap&&【NOIP模拟赛】Weed 线段树的分治维护
线段树是一种作用于静态区间上的数据结构,可以高效查询连续区间和单点,类似于一种静态的分治.他最迷人的地方在于“lazy标记”,对于lazy标记一般随我们从父区间进入子区间而下传,最终给到叶子节点,但还 ...
- 【8.26校内测试】【重构树求直径】【BFS模拟】【线段树维护DP】
题目性质比较显然,相同颜色联通块可以合并成一个点,重新建树后,发现相邻两个点的颜色一定是不一样的. 然后发现,对于一条链来说,每次把一个点反色,实际上使点数少了2个.如下图 而如果一条链上面有分支,也 ...
- [CSP-S模拟测试]:影魔(树状数组+线段树合并)
题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...
- 【模拟8.10】Weed(线段树)
考试只好随便骗骗分过去啦啦啦..... 正解是玄学线段树: 以每个操作为叶子节点,我们定义几个变量ce表示层数,h表示高度,add表示所减的层数 那么问题转化为单点修改的问题输出直接是根节点答案 但是 ...
- BZOJ2040[2009国家集训队]拯救Protoss的故乡——模拟费用流+线段树+树链剖分
题目描述 在星历2012年,星灵英雄Zeratul预测到他所在的Aiur行星在M天后会发生持续性暴雨灾害,尤其是他们的首都.而Zeratul作为星灵族的英雄,当然是要尽自己最大的努力帮助星灵族渡过这场 ...
- 2018.10.20 NOIP模拟 蛋糕(线段树+贪心/lis)
传送门 听说是最长反链衍生出的对偶定理就能秒了. 本蒟蒻直接用线段树模拟维护的. 对于第一维排序. 维护第二维的偏序关系可以借助线段树/树状数组维护逆序对的思想建立权值线段树贪心求解. 代码
- 【Foreign】Weed [线段树]
Weed Time Limit: 20 Sec Memory Limit: 512 MB Description 从前有个栈,一开始是空的. 你写下了 m 个操作,每个操作形如 k v : 若 k ...
- CF280D-k-Maximum Subsequence Sum【模拟费用流,线段树】
正题 题目链接:https://www.luogu.com.cn/problem/CF280D 题目大意 一个长度为\(n\)的序列,\(m\)次操作 修改一个数 询问一个区间中选出\(k\)段不交子 ...
随机推荐
- layer的两种提示信息
layer.msg('您的航班价格已变动,请返回重新选择航班!', { time: 10000, shade : [0.6 , '#000' , true], btn: ['返回列表', '关闭'], ...
- 题解luoguP2054 BZOJ1965【[AHOI2005]洗牌】
题目链接: https://www.luogu.org/problemnew/show/P2054 https://www.lydsy.com/JudgeOnline/problem.php?id=1 ...
- NSIS逻辑函数头文件介绍
!include "LogicLib.nsh"使用 NSIS 的宏来提供各种逻辑基本语句,不需要预先添加函数. 基本语句 If|Unless..{ElseIf|ElseUnless ...
- LeetCode 腾讯精选50题--数组中的第K个最大元素
好吧,不得不承认,书上看到的始终不是自己的,只有亲身时间过才会明白该怎么操作. 找数组中第K个最大元素,简而言之就是先排序,不论使用哪种算法,都需要先排序,确认位置,由于数组可以通过下标直接访问,所以 ...
- 【Git的基本操作二】添加、提交、查看状态
添加.提交.查看状态操作 查看状态: git status
- JavaScript中变量声明效率问题
1 var theString1 = "字符串1"; var theString2 = "字符串1"; var theString3 = "字符串1& ...
- maven入门--part2 安装
Maven安装和配置 (1)下载安装文件apache-maven-3.03-bin.tar (2)解压至安装目录,安装完毕 (3)修改.bash_profile,修改maven安装路径,修改构建GC配 ...
- JVM学习(三):垃圾回收算法
局部性原理和分代回收思想 大学学习操作系统或者计算机组成原理的时候都提到一个重要概念,叫局部性原理. 局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小 ...
- ffmpeg处理视频命令
一:视频添加图片水印 ffmpeg -i a.mp4 -vf "movie=a.jpg[watermark];[in][watermark] overlay=main_w-overlay_w ...
- fastadmin 中的日期时间,日期时间范围范围插件和key-value插件
//A/a代表字段名<div class="form-group"> <label class="control-label col-xs-12 col ...