[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\)段不交子 ...
随机推荐
- 使用.netcore部署window服务完成过程(使用nssm,Topshelf)
一,新建.netcore控制台应用程序.本文使用.netcore2.2版本,结构如下 二,negut引用Topshelf.Log4Net,Topshelf 三,代码如下:1>Program.cs ...
- MVC4中去掉浏览器生成的无关代码方法
通过增加Web.Config配置,如: <add key="vs:EnableBrowserLink" value="false"/>可以去掉MVC ...
- O035、Nova Suspend / Rescue 操作详解
参考https://www.cnblogs.com/CloudMan6/p/5503501.html Suspend / Resume 有时候需要长时间暂停 instance , 可以通过 S ...
- java面试1
1.面向对象的特征·有·哪些方面 1)抽象 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节.抽 ...
- 三主机配置 keepalived VIP高可用
三台主机: 192.168.33.134 192.168.33.136 192.168.33.137 实验前: 关闭selinux 和iptables 1). 192.168.33.134 ...
- 1 SQL SERVER 实现字符串分割成table的方法
CREATE FUNCTION [dbo].[fn_SplitStringToTable] ( @p_Input VARCHAR(MAX), @p_Delimeter CHAR() = ',' ) R ...
- (十三)Linux sysfs device_attribute
/*************************************************************************** * Linux sysfs device_at ...
- kettle Spoon.bat闪退解决办法
1.Java环境配置问题 java_home:D:\Program Files\Java\jdk1.7.0_25(安装jdk路径) classpath:.;%java_home%\lib\dt.jar ...
- C++归并排序(数组&链表)
1.归并排序(Merge Sort) 归并排序的性能不受输入数据的影响,始终都是O(n log n)的时间复杂度.代价是需要额外的内存空间. 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采 ...
- linux基础—课堂随笔_03 SHELL脚本编程基础
shell脚本编程基础 条件选择:if语句 选择执行: 注意:if语句可嵌套 单分支 if(开头)判断条件:then条件为真的分支代码 fi(结尾) 双分支 if(开头)判断条件:then条件为真的分 ...