Luogu 45887 全村最好的嘤嘤刀(线段树 树状数组)
https://www.luogu.org/problemnew/show/T45887
题目背景
重阳节到了,我们最好的八重樱拥有全村最好的嘤嘤刀……
题目描述
在绯玉丸力量的影响下,八重村成了一条长度为 nnn 的八重街,并且绯玉丸可以带着八重樱出现在街上的任意地点。而我们的八重樱则会在街上任意穿梭来获取某一地点上的嘤嘤嘤能量,用以升级她的嘤嘤刀。
在每个时刻,都会发生以下 333 个事件:
111 xxx valvalval 表示在 xxx 地点出现了携带着 valvalval 点嘤嘤嘤能量的绯狱丸,并且绯狱丸会吞噬该点的嘤嘤嘤能量,使得该点的嘤嘤嘤能量变为 val−ai val - a_ival−ai 点,aia_iai 为出现绯狱丸的前一刻,该点所存在的嘤嘤嘤能量。
222 lll rrr 表示绯玉丸会带着八重樱出现在[ lll , rrr ]间的任意一点。八重樱为了尽快升级她的嘤嘤刀,会获取该区间上最大的嘤嘤嘤能量。特殊的,为了保卫八重村,当 lll , rrr 之间存在绯狱丸时,八重樱会优先用她的嘤嘤刀对付绯狱丸,并获得绯狱丸此时拥有的 aia_iai 点嘤嘤嘤能量。
333 lll rrr valvalval 绯玉丸会嘤嘤嘤,使得[ lll , rrr ]上的每一个地点的嘤嘤嘤能量增加 valvalval 点(包括绯狱丸)。
输入输出格式
输入格式:
第一行为 222 个数 nnn , mmm。
第二行为 nnn 个数,分别表示八重街上每个地点的初始嘤嘤嘤能量。
接下来 mmm 行,每行会发生 333 个事件中的一个,输入格式为题目描述中的格式。
输出格式:
对于每一个事件 222 ,你应当输出八重樱在该事件中获取的嘤嘤嘤能量并换行。
当所有事件结束时,如果嘤嘤刀积累的能量小于 100001000010000 ,你应当输出 QAQQAQQAQ 。
如果在[ 100001000010000 , 100000001000000010000000 )间,你应当输出 SakuraSakuraSakura。
如果都不符合,请输出 iceiceice。
输入输出样例
复制
10 10
1 2 3 4 5 6 7 8 9 10
2 1 10
2 1 10
2 1 10
2 1 10
2 1 10
2 1 10
2 1 10
2 1 10
2 1 10
2 1 10
10
9
8
7
6
5
4
3
2
1
QAQ
10 11
0 0 0 0 0 0 0 0 0 0
3 1 10 1
3 2 10 1
3 3 10 1
3 4 10 1
3 5 10 1
3 6 10 1
3 7 10 1
3 8 10 1
3 9 10 1
3 10 10 1
2 1 10
10
QAQ
10 13
0 0 0 0 0 0 0 0 0 0
1 10 10000
1 9 9000
1 8 8000
1 7 7000
1 6 6000
1 5 5000
1 4 4000
1 3 3000
1 2 2000
1 1 1000
2 10 10
2 8 8
2 8 10
10000
8000
9000
Sakura
说明
对于所有的数据:
最终答案都会在 [0,231−1][0,2^{31}-1][0,231−1] 范围内;
nnn , mmm ⩽\leqslant⩽ 100000100000100000。
值得注意的是,无论八重樱是获取了某一地点的嘤嘤嘤能量还是击败了某一地点的绯狱丸,该地点的嘤嘤嘤值都应当清零而不是保留原来的数值。
对于事件 222 ,题目保证每个事件中最多出现 111 只绯狱丸。
解题思路:
看过题目之后就应该知道这题肯定与线段树有关。
这题的难点应该是事件二,如何维护区间内是否有绯狱丸以及绯狱丸的位置,还有如何快速实现删除操作。
对于事件1,:只是一个单点修改的操作,线段树维护就行了。
对于事件3:只是一个区间加法的操作,线段树维护lazy标记,记得下传就行了。
对于事件2:先考虑[x,y]区间内没有绯狱丸的情况,只需要查询区间最大值及其位置,至于删除无非就是将最大值删除,可以转换为将最大值所在位置清零,用单点修改便可实现。
重点在于[x,y]区间有绯狱丸的情况,仔细阅读题目说明可以知道最多出现1只绯狱丸,由于我们是需要执行删除操作的,所以必须知道该绯狱丸所在的位置,这时我们就可以用树状数组来实现了,考虑用树状数组,在x位置加上值x,查询的时候至于要知道[x,y]区间的值是否为0即可,如果不为0,那么绯狱丸所在的位置便是查询的结果,再用线段树实现单点修改就行了,可谓妙啊!
由于这题代码量较大,至今我的代码还没过 QWQ,所以只好贴标程了,自己的等A了之后再来填坑吧~~~
思路是一致的,只是实现方面上略微不同。
标程:
#include <iostream>
#include <cstdio>
using namespace std; int n,m;
int last_ans=;
int p,x,y,v;
int se_tree[+];
int add[*+];//因为重载了max,所以延迟标记要单独出来 struct node
{
int maxx;
int max_place;
friend node max(node a,node b)
{
return a.maxx>b.maxx ? a:b;
}//重载max
} tree[*+]; inline int read()
{
int ans;
char c;
bool op=false;
while(c=getchar(),c<''||c>'')
{
if(c=='-') op=true;
}
ans=c-'';
while(c=getchar(),c>=''&&c<='')
{
ans=ans*+c-'';
}
return op? -ans:ans;
} void build(int l,int r,int num)
{
if(l==r)
{
tree[num].maxx=read();
tree[num].max_place=l;
return;
}
int mid=(l+r)>>;
build(l,mid,num<<);
build(mid+,r,num<<|);
tree[num]=max(tree[num<<],tree[num<<|]);
} inline void spread(int l,int r,int num)
{
if(add[num])
{
int mid=(l+r)>>;
tree[num<<].maxx+=add[num];
tree[num<<|].maxx+=add[num];
add[num<<]+=add[num];
add[num<<|]+=add[num];
add[num]=;
}
} void appear(int l,int r,int L,int val,int num)
{
if(l==r)
{
tree[num].maxx=val-tree[num].maxx;
return;
}
int mid=(l+r)>>;
spread(l,r,num);
if(mid<L) appear(mid+,r,L,val,num<<|);
else appear(l,mid,L,val,num<<);
tree[num]=max(tree[num<<],tree[num<<|]);
} node ask(int l,int r,int L,int R,int num)
{
if(l==L&&r==R)
{
return tree[num];
}
int mid=(l+r)>>;
spread(l,r,num);
if(mid<L) return ask(mid+,r,L,R,num<<|);
else if(mid>=R) return ask(l,mid,L,R,num<<);
else return max(ask(l,mid,L,mid,num<<),ask(mid+,r,mid+,R,num<<|));
} void change(int l,int r,int L,int R,int val,int num)
{
if(l==L&&r==R)
{
tree[num].maxx+=val;
add[num]+=val;
return;
}
int mid=(l+r)>>;
spread(l,r,num);
if(mid<L) change(mid+,r,L,R,val,num<<|);
else if(mid>=R) change(l,mid,L,R,val,num<<);
else change(l,mid,L,mid,val,num<<),change(mid+,r,mid+,R,val,num<<|);
tree[num]=max(tree[num<<],tree[num<<|]);
} inline void se_add(int x,int val)
{
for(; x<=n; x+=x&-x) se_tree[x]+=val;
} inline int se_ask(int x)
{
int ans=;
for(; x; x-=x&-x) ans+=se_tree[x];
return ans;
} int main()
{
n=read();
m=read();
build(,n,);
while(m--)
{
p=read();
if(p==)
{
x=read();
v=read();
appear(,n,x,v,);
se_add(x,x);
}
else if(p==)
{
x=read();
y=read();
int num=se_ask(y)-se_ask(x-);
if(num)
{
node ans=ask(,n,num,num,);
printf("%d",ans.maxx);
putchar('\n');
last_ans+=ans.maxx;
change(,n,num,num,-ans.maxx,);
se_add(num,-num);
continue;
}
node ans=ask(,n,x,y,);
change(,n,ans.max_place,ans.max_place,-ans.maxx,);
printf("%d",ans.maxx);
putchar('\n');
last_ans+=ans.maxx;
}
else
{
x=read();
y=read();
v=read();
change(,n,x,y,v,);
}
}
if(last_ans<) printf("QAQ");
else if(last_ans<) printf("Sakura");
else printf("ice"); return ;
}
2018-10-22 11:09:32:
程序AC啦,原来是个lxl题,题目竟然没有Special Judge???!!!,如果区间有多个最大值得话,删除哪一个并不确定,我的程序默认删除左儿子但是std默认删除右儿子。。。
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 100009
#define maxm
inline ll read()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ll)(ch-'');ch=getchar();}
return x*f;
}
#define ls(x) x<<1
#define rs(x) x<<1|1
int val[maxn],mx[maxn<<],add[maxn<<],pos[maxn<<],c[maxn];
int n,m,k,tot,cnt,mxp,tot_ans=;
void insert(int x,int y)
{
while(x<=n)
{
c[x]+=y;
x+=(x&(-x));
}
} int Query_have(int x)
{
int sum=;
while(x)
{
sum+=c[x];
x-=(x&(-x));
}
return sum;
} void push_up(int x)
{
mx[x]=mx[rs(x)],pos[x]=pos[rs(x)];
if(mx[x]<mx[ls(x)])
mx[x]=mx[ls(x)],pos[x]=pos[ls(x)];
} void push_down(int x)
{
add[ls(x)]+=add[x];
mx[ls(x)]+=add[x];
add[rs(x)]+=add[x];
mx[rs(x)]+=add[x];
add[x]=;
} void built(int x,int l,int r)
{
if(l==r)
{
mx[x]=val[l];
pos[x]=l;
return ;
}
int mid=(l+r)>>;
built(ls(x),l,mid);
built(rs(x),mid+,r);
push_up(x);
} void Add(int x,int l,int r,int nl,int nr,int k)
{
if(nl<=l&&r<=nr)
{
add[x]+=k;
mx[x]+=k;
return ;
}
push_down(x);
int mid=(l+r)>>;
if(nl<=mid)
Add(ls(x),l,mid,nl,nr,k);
if(mid<nr)
Add(rs(x),mid+,r,nl,nr,k);
push_up(x);
} void Update(int x,int l,int r,int p,int k,int f)
{
if(l==r)
{
if(!f)
mx[x]=k-mx[x];
else
mx[x]=;
return ;
}
push_down(x);
int mid=(l+r)>>;
if(p<=mid)
Update(ls(x),l,mid,p,k,f);
else
Update(rs(x),mid+,r,p,k,f);
push_up(x);
} pair<int,int> Query(int x,int l,int r,int nl,int nr)
{
pair <int,int> ans;ans.first=-INF;
if(nl<=l&&r<=nr)
return make_pair(mx[x],pos[x]);
push_down(x);
int mid=(l+r)>>;
if(mid<nr)
ans=Query(rs(x),mid+,r,nl,nr);
if(nl<=mid)
{
pair <int,int> temp=Query(ls(x),l,mid,nl,nr);
if(temp.first>ans.first)
ans=temp;
}
return ans;
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
n=read(),m=read();
for(int i=;i<=n;i++)
val[i]=read();
built(,,n);
for(int i=;i<=m;i++)
{
int opt=read(),x=read(),y=read(),z;
if(opt==)
Update(,,n,x,y,),insert(x,x);
else if(opt==)
{
int id=Query_have(y)-Query_have(x-);
if(id)
{
pair <int,int> temp=Query(,,n,id,id);
printf("%d\n",temp.first);
tot_ans+=temp.first;
Update(,,n,temp.second,,);
insert(id,-id);
continue;
}
pair<int,int> temp=Query(,,n,x,y);
printf("%d\n",temp.first);
tot_ans+=temp.first;
Update(,,n,temp.second,,);
}
else
{
z=read();
Add(,,n,x,y,z);
}
}
if(tot_ans<)
puts("QAQ");
else if(tot_ans<)
puts("Sakura");
else
puts("ice");
fclose(stdin);
fclose(stdout);
return ;
}
Luogu 45887 全村最好的嘤嘤刀(线段树 树状数组)的更多相关文章
- Luogu 3373 又乘又加的线段树
Luogu 3373 又乘又加的线段树 当给一个节点加上一个加法标记时,直接把加法标记 += 新值: 当给一个节点加上一个乘法标记时,把乘法标记和加法标记同时 *= 新值.(注意pushdown函数中 ...
- [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...
- [luogu P3801] 红色的幻想乡 [线段树][树状数组]
题目背景 蕾米莉亚的红雾异变失败后,很不甘心. 题目描述 经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放. 我们将幻想乡看做是一个n*m的方格地区,一 ...
- 线段树合并 || 树状数组 || 离散化 || BZOJ 4756: [Usaco2017 Jan]Promotion Counting || Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数
题面:P3605 [USACO17JAN]Promotion Counting晋升者计数 题解:这是一道万能题,树状数组 || 主席树 || 线段树合并 || 莫队套分块 || 线段树 都可以写..记 ...
- 树状数组 || 线段树 || Luogu P5200 [USACO19JAN]Sleepy Cow Sorting
题面:P5200 [USACO19JAN]Sleepy Cow Sorting 题解: 最小操作次数(记为k)即为将序列倒着找第一个P[i]>P[i+1]的下标,然后将序列分成三部分:前缀部分( ...
- luogu P5142 区间方差 十分优美的线段树
又来了个维护方差的线段树.... 大致推导过程(字丑多包涵QAQ) 注意取模时要加一些100000007防止出现负数.. #include<cstdio> #include<iost ...
- luogu P4632 [APIO2018] New Home 新家 线段树 set 二分
写了一种比较容易理解 但是常数很大的sol. 容易发现可以扫描线. 维护好序列之后发现很难查距离 考虑二分. 这里二分可以在线段树上进行 当然可能存在一些问题 如果离散化的话需要处理一些比较麻烦的细节 ...
- st表、树状数组与线段树 笔记与思路整理
已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...
- P3688 [ZJOI2017] 树状数组 【二维线段树】
题目描述:这里有一个写挂的树状数组: 有两种共\(m\)个操作: 输入\(l,r\),在\([l,r]\)中随机选择一个整数\(x\)执行\(\text{Add}(x)\) 输入\(l,r\),询问执 ...
随机推荐
- python的内置模块xml模块方法 xml解析 详解以及使用
一.XML介绍 xml是实现不同语言或程序直接进行数据交换的协议,跟json差不多,单json使用起来更简单,不过现在还有很多传统公司的接口主要还是xml xml跟html都属于是标签语言 我们主要学 ...
- saltstack主机管理项目:主机管理项目需求分析(一)
1.场景: 我现在又一台裸机要实现一下任务 2.配置管理: 1.装上nginx,mysql 2.nginx用我指定的配置文件 3.mysql用户 4.设置一个默认的数据库访问权限 5.启动mysql ...
- ajax扩展、jsonp、
偷偷上传消息,首先想到ajax 而ajax是jquery是我们封装的功能. 方式一:ajax发消息 $.ajax({ url: '/ajax3.html', type: 'GET', //或者是POS ...
- metasploit 教程之基本参数和扫描
前言 首先我也不知道我目前的水平适不适合学习msf. 在了解一些msf之后,反正就是挺想学的.就写博记录一下.如有错误的地方,欢迎各位大佬指正. 感激不尽.! 我理解的msf msf全程metaspl ...
- win2003 创建nds辅助服务器 步骤
准备条件:win2003系统DNS主机 win2003系统 DNS副机 在同一局域网下: 目标.新建个laohu.com 主机并添加副机 再 正向查找区域 右键新建区域---下一步--- 选择主要区 ...
- input全选和取消全选
<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...
- 【转载】Jenkins安装以及邮件配置
转载:http://www.nnzhp.cn/archives/590 Jenkins介绍 Jenkins是一个java开发的.开源的.非常好用持续集成的工具,它能帮我们实现自动化部署环境.测试.打包 ...
- TestNg和spring3测试报错:Failed to read candidate component class-遁地龙卷风
java.lang.IllegalStateException:Failed to load ApplicationContext Caused by: org.springframework.bea ...
- lsof/netstat命令的一个重要作用: 根据进程查端口, 根据端口查进程
我们知道, 根据ps -aux | grep xxx就是很快实现进程名和进程号的互查, 所以我们只说进程号pid就行. 如下示例中, 进程pid常驻. 1. 根据进程pid查端口: lsof -i ...
- 找不多控件, or 控件为null
组件化开发,命名要使用moudle区分, 同名,在最后合成的时候,会出现很多问题,