线段树秀操作题。

奇怪的计算器

有 N 个数,一共会对这 N 个数执行 M 个指令(对没个数执行的指令都一样),每一条指令可以是以下四种指令之一:(这里 a 表示一个正整数)

  1. 加上 a
  2. 减去 a
  3. 乘以 a
  4. 加上 a*X(X 是数最开始的初值)

该计算器有个奇怪的特点。每进行一个指令,若结果大于 R则变成 R,同理若结果小于 L,则变成 L。求这 N 个数最后的结果。

N, M ≤ 200000

题解

重要性质:无论题目里面的修改怎么执行,所有数的相对大小(即排名)不变。所以我们每次的chkmin和chkmax操作肯定是对一个排序后的后缀和前缀区间进行的。那么我们成功地将不连续的问题转化成了连续的问题。

所以我们可以针对题目设计懒标记 x=t1*x+t2*x0+t3。懒标记的合并很显然,而由于排名不变,所以区间的最大最小值还是很好维护的。

时间复杂度 O(n log n)。

CO int N=100000+10;
int L,R;
pair<int,int> p[N],q[N]; LL t1[4*N],t2[4*N],t3[4*N];
LL lp[4*N],rp[4*N],mn[4*N],mx[4*N];
#define lc (x<<1)
#define rc (x<<1|1)
void build(int x,int l,int r){
t1[x]=1,t2[x]=t3[x]=0;
lp[x]=mn[x]=q[l].first,rp[x]=mx[x]=q[r].first;
if(l==r) return;
int mid=(l+r)>>1;
build(lc,l,mid),build(rc,mid+1,r);
}
IN void push_up(int x){
mn[x]=mn[lc],mx[x]=mx[rc];
}
IN void add_tag(int x,LL k1,LL k2,LL k3){
t1[x]*=k1,t2[x]=k1*t2[x]+k2,t3[x]=k1*t3[x]+k3;
mn[x]=k1*mn[x]+k2*lp[x]+k3,mx[x]=k1*mx[x]+k2*rp[x]+k3;
}
IN void push_down(int x){
if(t1[x]!=1 or t2[x] or t3[x]){
add_tag(lc,t1[x],t2[x],t3[x]);
add_tag(rc,t1[x],t2[x],t3[x]);
t1[x]=1,t2[x]=t3[x]=0;
}
}
void chkl(int x){
if(mn[x]>=L) return;
if(mx[x]<=L) return add_tag(x,0,0,L);
push_down(x);
if(mx[lc]<=L) add_tag(lc,0,0,L),chkl(rc);
else chkl(lc);
push_up(x);
}
void chkr(int x){
if(mx[x]<=R) return;
if(mn[x]>=R) return add_tag(x,0,0,R);
push_down(x);
if(mn[rc]>=R) add_tag(rc,0,0,R),chkr(lc);
else chkr(rc);
push_up(x);
} int ans[N]; void query(int x,int l,int r){
if(l==r){
ans[q[l].second]=mn[x];
return;
}
push_down(x);
int mid=(l+r)>>1;
query(lc,l,mid),query(rc,mid+1,r);
} int main(){
int n=read<int>();
read(L),read(R);
for(int i=1;i<=n;++i){
char opt[2];scanf("%s",opt);
if(opt[0]=='+') p[i].first=1;
else if(opt[0]=='-') p[i].first=2;
else if(opt[0]=='*') p[i].first=3;
else p[i].first=4;
read(p[i].second);
}
int m=read<int>();
for(int i=1;i<=m;++i) read(q[i].first),q[i].second=i;
sort(q+1,q+m+1);
build(1,1,m);
for(int i=1;i<=n;++i){
if(p[i].first==1) add_tag(1,1,0,p[i].second);
else if(p[i].first==2) add_tag(1,1,0,-p[i].second);
else if(p[i].first==3) add_tag(1,p[i].second,0,0);
else add_tag(1,1,p[i].second,0);
if(mx[1]>R) chkr(1);
if(mn[1]<L) chkl(1);
}
query(1,1,m);
for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
return 0;
}

Gorgeous Sequence

There is a sequence a of length n. We use ai to denote the i-th element in this sequence. You should do the following three types of operations to this sequence.

0 x y t: For every x≤i≤y, we use min(ai,t) to replace the original ai's value.

1 x y: Print the maximum value of ai that x≤i≤y.

2 x y: Print the sum of ai that x≤i≤y.

分析

吉司机线段树板子题。

1和2操作很简单,0操作很难,一个一个改时间肯定不允许,但是又没什么办法可以直接全改掉。

结合题目问的是区间最大值和区间和,那么就思考操作 0 会对区间最大值和区间和有什么影响,于是就有了以下方法:

维护 3 个值,区间最大值,区间严格次大值,区间最大值的个数。然后我们每次做0操作的时候,就会有3种情况。

  1. t >= 区间最大值, 这时每个值都不用修改,直接返回。
  2. 区间次大值 < t < 区间最大值,此时只有最大值会变,又已经求得了最大值的个数,所以我们可以直接更新这段的sum和max。
  3. 其他情况。无法直接对当前情况修改,所以继续搜两个儿子,直到搜到前两种情况为止。

我们可以把区间的最大值看做是这个区间的标记,因为每次更新的时候只会更新到(区间次大值 < t < 区间最大值)的情况,然后会修改sum和max,所以以后一旦进入这个区间的子树,必须先更新这个子树的max和sum。于是就有了pushdown()的写法,它就是负责把当前区间的sum和mx信息传给子树。

const int MAXN=1e6+7;

int ql,qr,v;

struct SegTree
{
ll sum[MAXN<<2];
int maxv[MAXN<<2],num[MAXN<<2],secv[MAXN<<2];
#define lson (now<<1)
#define rson (now<<1|1)
inline void pushup(int now)
{
sum[now]=sum[lson]+sum[rson];
maxv[now]=max(maxv[lson],maxv[rson]);
if(maxv[lson]==maxv[rson])
{
num[now]=num[lson]+num[rson];
secv[now]=max(secv[lson],secv[rson]);
}
else
{
num[now]=maxv[lson]>maxv[rson]?num[lson]:num[rson];
secv[now]=max(secv[lson],secv[rson]);
secv[now]=max(secv[now],min(maxv[lson],maxv[rson]));
}
} void build(int now,int l,int r)
{
if(l==r)
{
sum[now]=_read();
maxv[now]=sum[now];
num[now]=1;
secv[now]=-1;
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(now);
} inline void puttag(int now,int x)
{
if(x>=maxv[now])
return;
sum[now]-=(ll)num[now]*(maxv[now]-x);
maxv[now]=x;
} inline void pushdown(int now)
{
puttag(lson,maxv[now]);
puttag(rson,maxv[now]);
} void change(int now,int l,int r)
{
if(v>=maxv[now])
return;
if(ql<=l&&r<=qr&&secv[now]<v)
{
puttag(now,v);
return;
}
pushdown(now);
int mid=(l+r)>>1;
if(ql<=mid)
change(lson,l,mid);
if(qr>=mid+1)
change(rson,mid+1,r);
pushup(now);
} ll qmax(int now,int l,int r)
{
if(ql<=l&&r<=qr)
{
return maxv[now];
}
pushdown(now);
int mid=(l+r)>>1;
ll ans=0;
if(ql<=mid)
ans=max(ans,qmax(lson,l,mid));
if(qr>=mid+1)
ans=max(ans,qmax(rson,mid+1,r));
return ans;
} inline ll qsum(int now,int l,int r)
{
if(ql<=l&&r<=qr)
{
return sum[now];
}
pushdown(now);
int mid=(l+r)>>1;
ll ans=0;
if(ql<=mid)
ans+=qsum(lson,l,mid);
if(qr>=mid+1)
ans+=qsum(rson,mid+1,r);
return ans;
}
}Tree; int n,m; int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
int T=_read();
while(T--)
{
n=_read();m=_read();
Tree.build(1,1,n);
while(m--)
{
int opt=_read();
if(opt==0)
{
ql=_read();qr=_read();v=_read();
Tree.change(1,1,n);
}
else if(opt==1)
{
ql=_read();qr=_read();
printf("%lld\n",Tree.qmax(1,1,n));
}
else if(opt==2)
{
ql=_read();qr=_read();
printf("%lld\n",Tree.qsum(1,1,n));
}
}
}
// fclose(stdin);
// fclose(stdout);
return 0;
}

BZOJ4695 最假女选手是这道题的复杂版。

AHOI2014 奇怪的计算器 和 HDU5306 Gorgeous Sequence的更多相关文章

  1. hdu5306 Gorgeous Sequence

    hdu5306 Gorgeous Sequence 题目大意 ​ 给你一个序列,维护区间和,区间chkmin和区间最大值 数据范围 数据组数T,序列长度n,操作次数m $T = 100,\sum n ...

  2. BZOJ 3878: [Ahoi2014]奇怪的计算器

    BZOJ 3878: [Ahoi2014]奇怪的计算器 标签(空格分隔): OI-BZOJ OI-线段树 Time Limit: 10 Sec Memory Limit: 256 MB Descrip ...

  3. [HDU5306]Gorgeous Sequence(标记回收线段树)

    题意:维护一个序列,支持区间与一个数取min,询问区间最大,询问区间和(序列长度<=1e6) 分析: http://www.shuizilong.com/house/archives/hdu-5 ...

  4. BZOJ3878: [Ahoi2014&Jsoi2014]奇怪的计算器

    BZOJ3878: [Ahoi2014&Jsoi2014]奇怪的计算器 Description [故事背景] JYY有个奇怪的计算器,有一天这个计算器坏了,JYY希望你能帮助他写 一个程序来模 ...

  5. 「AHOI2014/JSOI2014」奇怪的计算器

    「AHOI2014/JSOI2014」奇怪的计算器 传送门 我拿到这题首先是懵b的,因为感觉没有任何性质... 后来经过同机房dalao的指导发现可以把所有的 \(X\) 放到一起排序,然后我们可以发 ...

  6. BZOJ 3878 【AHOI2014】 奇怪的计算器

    题目链接:奇怪的计算器 如果没有溢出的话,所有的标记都可以在线段树上直接维护,所以一棵线段树就解决问题了. 现在有了溢出,怎么办呢? 发现就算溢出了,各个元素的相对大小关系也是不变的.所以,如果一开始 ...

  7. HDU 5306 Gorgeous Sequence[线段树区间最值操作]

    Gorgeous Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  8. 2015 Multi-University Training Contest 2 hdu 5306 Gorgeous Sequence

    Gorgeous Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  9. HDOJ 5306 Gorgeous Sequence 线段树

    http://www.shuizilong.com/house/archives/hdu-5306-gorgeous-sequence/ Gorgeous Sequence Time Limit: 6 ...

随机推荐

  1. ef core 全局过滤

    有些固定的条件,基本每个查询的时候需要带的条件,我们可以使用全局过滤来帮我们,这样后面的查询就不用每次都带条件了. 微软自带的:https://docs.microsoft.com/zh-cn/ef/ ...

  2. prometheus使用postgresql-adapter连接postgresql

    概述 Prometheus使用postgresql需要使用postgresql-adapter进行数据转换.在安装postgresql-adapter之前需要安装2个扩展:pg_prometheus和 ...

  3. SSL密钥协商过程分析

    一.说明 尽管做过证书生成.双向认证.SSL通信编程等事情,但一直不清楚SSL如何完成密钥交换.看网上的资料则众说纷纭,最近和朋友学习时聊到了这个问题,然后正巧上周处理客户反馈SSL版本过低时领导也想 ...

  4. 生成Makefile文件全过程

    [1]生成Makefile文件全过程 整体流程如下图: 注意:以下文件根目录为testmake(任意位置新建即可) (1)测试程序 1.1 建立两个目录:mkdir include source 1. ...

  5. Go语言系列教程(十二)之函数完结篇

    Hello,各位小伙伴大家好,我是小栈君.上一期我们讲到了关于函数的有参.无参.匿名函数,本期我们分享一下关于go语言函数类型.匿名函数和闭包的概念和实战.闲话不多说,立马开始分享. 在Go语言中,函 ...

  6. Elasticsearch常见用法-分布式集群

    集群内部工作方式 Elasticsearch用于构建高可用和可扩展的系统.扩展的方式可以是购买更好的服务器(纵向扩展(vertical scale or scaling up))或者购买更多的服务器( ...

  7. JAAS configuration for Kafka clients

    Clients may configure JAAS using the client configuration property sasl.jaas.config or using the sta ...

  8. 2019 中钢网java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.中钢网等公司offer,岗位是Java后端开发,因为发展原因最终选择去了中钢网,入职一年时间了,也成为了面试官 ...

  9. Spring Cloud的常规组件和简单实战(一)

    最近一段时间在学习Spring Cloud,从Eureka到Hystrix,常用的配置和方法都有涉及一些,以此笔记来记录一下学习到的东西,也分享一下.内容以实战为起点,主要以介绍常规用法为主,最后也会 ...

  10. .net core web api 默认的模型验证

    转载自 https://www.codercto.com/a/45938.html