sdoir1考挂,本来都要退役了。。。结果还是进了二轮末尾。。。打算混个D类去养老;

最近有点颓,需要写些东西和学些新东西止一下颓势,就先把这几星期前学的神奇线段树写了吧。。。

吉司机线段树主要是用来解决序列区间上满足部分满足一定性质的修改操作的,比方说把区间中小于x的数改成x,大于x的数改成x,甚至是区间取并和区间取或(实际上也就是区间中的每个数的每一位进行类似小于x改成x那种操作)

这玩意的复杂的是很玄学的,好像要用到势能分析一类的;不过正常情况下复杂度最坏也就nlogn^2,可以放心用啦
两年之后补充一下,复杂度吉老师已经证明,若不进行区间加减是均摊nlogn.具体证明可从codeforces上找,在1290E的题解里有链接.

下面主要说一下怎么处理区间中把小于x 的数改成x,其他的可以类比来做;

首先要记一个中间量,也就是次小值;然后再把线段树上每一个区间的最小值及其个数记录下来;

对于每次修改,设要和x进行对比;

如果当前找到的区间的最小值>=x,那么肯定没必要再往下处理了;

如果x>最小值但x<次小值(注意x严格小于次小值)那么只需要把最小值改成x,记录的最小值的数目都不需要改,这样线段树上维护的其他信息也可以很方便的修改(例如区间和一类的信息)

如果x>=次小值,那递归处理左右子区间再合并信息回来;

算法的描述感觉大家都是千篇一律。。。实际写起来细节也挺多的,例如如果对最小值修改成x,要单独记到一个标记数组里,标记下传的顺序也需要仔细考虑;
其实我今天之所以会想到写这个,主要是在bzoj上做了一道相关的题,然后怎么都tle;
实际和别人比起来效率也没差多少。。。
那题是同时有两种操作,标记的合并上又有很多其他细节;
那么就放一下我卡常失败的代码,等bzoj换评测机了之后再去交吧。。。

时隔多年,我再来贡献一种实现比较方便的写法
这种写法综合了oi-wiki及我一个学长的写法
其实只需要记一下最值,次最值即可,不必单独为这类操作加个标记数组.
对于同时需要取min和取max的题目,不妨先说取min,此时需要对最大值进行操作.假设对区间进行对x取min的操作(大于x的改为x)
先说如何修改.
当递归到符合修改条件的节点(修改区间包含当前节点,且最大值大于x,次大值小于x)时,直接将最大值改为x即可.
再说如何下传标记.
其实直接将当前节点最大值当作修改值传给儿子就好.
因为当前节点是修改过的,所有值都小于等于x,对儿子节点所有值与 xxx 取min 其实等价于对儿子节点所有值与 当前节点最大值当前节点最大值当前节点最大值 取min,并且只要判断下儿子最大值是否需要修改即可,儿子的次大值肯定会小于当前节点最大值.
至于解决最大值和最小值数组冲突的问题,在取min操作时,只要判断一下修改前最大值是否等于最小值和次小值,最大值等于哪个就把哪个改为修改后的值.因为出现冲突只有可能当前区间的不同值个数小于2,区间只有一个值时最大值等于最小值,只有两个值时最大值等于次小值.
注意初始化时若区间只有一种数,次小值赋为极大,次大值赋为极小.
具体新的写法贴到文章最后了,虽然人丑大常数还是没过bzoj,不过我自测后正确性应该是没问题的.
两年前的老代码就不删了…

题目:bzoj 4695


#include<ctime>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define cmp(x,y,ck) (ck? x>y:x<y)
const int inf=2e9;
const int maxn=500005;
LL sum[maxn<<2];
int mv[maxn<<2][2],smv[maxn<<2][2],mvn[maxn<<2][2],a[maxn],col[maxn<<2],mcol[maxn<<2][2];
inline int MV(int x,int y,int ck){if((ck&&x>y)||(!ck&&x<y))return x;else return y;
}
inline void updata(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];for(int ck=0;ck<2;ck++)if(mv[rt<<1][ck]==mv[rt<<1|1][ck]){mv[rt][ck]=mv[rt<<1][ck];mvn[rt][ck]=mvn[rt<<1][ck]+mvn[rt<<1|1][ck];smv[rt][ck]=MV(smv[rt<<1][ck],smv[rt<<1|1][ck],ck);}else{int tp=(cmp(mv[rt<<1][ck],mv[rt<<1|1][ck],ck)^1);mv[rt][ck]=mv[(rt<<1)^tp][ck];mvn[rt][ck]=mvn[(rt<<1)^tp][ck];smv[rt][ck]=MV(smv[(rt<<1)^tp][ck],mv[(rt<<1|1)^tp][ck],ck);        }
}
inline void color(int l,int r,int rt,int v){sum[rt]+=(LL)(r-l+1)*v;mv[rt][0]+=v;mv[rt][1]+=v;col[rt]+=v;if(smv[rt][0]!=inf)smv[rt][0]+=v;if(smv[rt][1]!=-inf)smv[rt][1]+=v;
}
inline void mcolor(int rt,int ck,int v){if(mv[rt][ck]==mv[rt][ck^1]){mv[rt][ck^1]+=v;mcol[rt][ck^1]+=v;}if(mv[rt][ck]==smv[rt][ck^1])smv[rt][ck^1]+=v;mv[rt][ck]+=v;sum[rt]+=(LL)mvn[rt][ck]*v;mcol[rt][ck]+=v;
}
inline void pushcol(int l,int r,int rt){if(col[rt]){int mid=(l+r)>>1;color(lson,col[rt]);color(rson,col[rt]);col[rt]=0;}for(int i=0;i<2;i++)if(mcol[rt][i]){if(mv[rt][i]==mv[rt<<1][i]+mcol[rt][i])mcolor(rt<<1,i,mcol[rt][i]);if(mv[rt][i]==mv[rt<<1|1][i]+mcol[rt][i])mcolor(rt<<1|1,i,mcol[rt][i]);}mcol[rt][0]=mcol[rt][1]=0;
}
inline void add(int l,int r,int rt,int nl,int nr,int v){if(nl<=l&&nr>=r){color(l,r,rt,v);return;}pushcol(l,r,rt);int mid=(l+r)>>1;if(nl<=mid)add(lson,nl,nr,v);if(nr>mid)add(rson,nl,nr,v);updata(rt);
}
inline void same(int l,int r,int rt,int v,int ck){if(!cmp(mv[rt][ck],v,ck))return;else if(cmp(v,smv[rt][ck],ck)){mcolor(rt,ck,v-mv[rt][ck]);return ;}pushcol(l,r,rt);int mid=(l+r)>>1;same(lson,v,ck);same(rson,v,ck);updata(rt);
}
inline void modify(int l,int r,int rt,int nl,int nr,int v,int ck){if(nl<=l&&nr>=r){same(l,r,rt,v,ck);return;}pushcol(l,r,rt);int mid=(l+r)>>1;if(nl<=mid)modify(lson,nl,nr,v,ck);if(nr>mid)modify(rson,nl,nr,v,ck);updata(rt);
}
inline LL querysum(int l,int r,int rt,int nl,int nr){while(!(nl<=l&&nr>=r)){pushcol(l,r,rt);int mid=(l+r)>>1;if(nl<=mid&&nr>mid)return querysum(lson,nl,nr)+querysum(rson,nl,nr);else if(nl<=mid)r=mid,rt<<=1;else l=mid+1,rt=rt<<1|1;}return sum[rt];
}
inline int querymv(int l,int r,int rt,int nl,int nr,int ck){while(!(nl<=l&&nr>=r)){pushcol(l,r,rt);int mid=(l+r)>>1;if(nl<=mid&&nr>mid)return MV(querymv(lson,nl,nr,ck),querymv(rson,nl,nr,ck),ck);else if(nl<=mid)r=mid,rt<<=1;else l=mid+1,rt=rt<<1|1;}return mv[rt][ck];
}
inline void build(int l,int r,int rt){col[rt]=mcol[rt][0]=mcol[rt][1]=0;if(l==r){mv[rt][0]=mv[rt][1]=a[l];mvn[rt][0]=mvn[rt][1]=1;smv[rt][0]=inf;smv[rt][1]=-inf;sum[rt]=(LL)a[l];return;} int mid=(l+r)>>1;build(lson);build(rson);updata(rt);
}
inline int read(){char c=getchar();int tv=0,ck=1; while(c<'0'||c>'9'){if(c=='-')ck=-1; c=getchar();} while(c>='0'&&c<='9'){tv=(tv<<1)+(tv<<3)+c-'0';c=getchar(); } return tv*ck;
}
int main()
{int n,m;n=read(); for(int i=1;i<=n;i++)a[i]=read();build(1,n,1); m=read();for(int i=1;i<=m;i++){int ck=read(),nl=read(),nr=read();if(ck<=3){int tv=read();if(ck==1)add(1,n,1,nl,nr,tv);else modify(1,n,1,nl,nr,tv,ck==3); }else if(ck==4)printf("%lld\n",querysum(1,n,1,nl,nr));else printf("%d\n",querymv(1,n,1,nl,nr,ck==5)); } return 0;
}
//更新后的写法
#include<bits/stdc++.h>
using namespace std;
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
#define LL long long
namespace SegmentTreeBeats{typedef LL T;#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1const T inf=1e9+7;const int maxn=5e5+5;T sum[maxn<<2],col[maxn<<2],v[maxn<<2];template<class cmp,T Inf>struct INFO{T mv,smv;int cnt;const static T INF=Inf;INFO operator + (const INFO& p)const{INFO ans;if(cmp()(mv,p.mv)){ans.mv=p.mv;ans.cnt=p.cnt;ans.smv=cmp()(mv,p.smv)?p.smv:mv;}else if(cmp()(p.mv,mv)){ans.mv=mv;ans.cnt=cnt;ans.smv=cmp()(smv,p.mv)?p.mv:smv;}else{ans.mv=mv;ans.cnt=cnt+p.cnt;ans.smv=cmp()(smv,p.smv)?p.smv:smv;}return ans;}};INFO<less<T>,-inf>Mx[maxn<<2];INFO<greater<T>,inf>Mn[maxn<<2];void updata(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];Mx[rt]=Mx[rt<<1]+Mx[rt<<1|1];Mn[rt]=Mn[rt<<1]+Mn[rt<<1|1];}void build(int l,int r,int rt){col[rt]=0;if(l==r){Mx[rt].mv=Mn[rt].mv=sum[rt]=v[l];Mx[rt].cnt=Mn[rt].cnt=1;Mx[rt].smv=Mx[rt].INF;Mn[rt].smv=Mn[rt].INF;return;}int mid=(l+r)>>1;build(lson);build(rson);updata(rt);}inline void color(int l,int r,int rt,T val){sum[rt]+=val*(r-l+1);col[rt]+=val;if(Mx[rt].smv!=-inf)Mx[rt].smv+=val;if(Mn[rt].smv!=inf)Mn[rt].smv+=val;Mx[rt].mv+=val,Mn[rt].mv+=val;}inline void colorToLess(int rt,T val){if(Mx[rt].mv<=val)return;sum[rt]+=(val-Mx[rt].mv)*Mx[rt].cnt;if(Mn[rt].smv==Mx[rt].mv)Mn[rt].smv=val;if(Mn[rt].mv==Mx[rt].mv)Mn[rt].mv=val;Mx[rt].mv=val;}inline void colorToMore(int rt,T val){if(Mn[rt].mv>=val)return;sum[rt]+=(val-Mn[rt].mv)*Mn[rt].cnt;if(Mx[rt].smv==Mn[rt].mv)Mx[rt].smv=val;if(Mx[rt].mv==Mn[rt].mv)Mx[rt].mv=val;Mn[rt].mv=val;}inline void pushcol(int l,int r,int rt){if(col[rt]){int mid=(l+r)>>1;color(lson,col[rt]);color(rson,col[rt]);col[rt]=0;}colorToLess(rt<<1,Mx[rt].mv);colorToLess(rt<<1|1,Mx[rt].mv);colorToMore(rt<<1,Mn[rt].mv);colorToMore(rt<<1|1,Mn[rt].mv);}void toLess(int l,int r,int rt,int nl,int nr,T val){if(Mx[rt].mv<=val)return;if(nl<=l&&nr>=r&&Mx[rt].smv<val){colorToLess(rt,val);return;}pushcol(l,r,rt);int mid=(l+r)>>1;if(nl<=mid)toLess(lson,nl,nr,val);if(nr>mid)toLess(rson,nl,nr,val);updata(rt);}void toMore(int l,int r,int rt,int nl,int nr,T val){if(Mn[rt].mv>=val)return;if(nl<=l&&nr>=r&&Mn[rt].smv>val){colorToMore(rt,val);return;}pushcol(l,r,rt);int mid=(l+r)>>1;if(nl<=mid)toMore(lson,nl,nr,val);if(nr>mid)toMore(rson,nl,nr,val);updata(rt);}void modify(int l,int r,int rt,int nl,int nr,T val){if(nl<=l&&nr>=r){color(l,r,rt,val);return ;}pushcol(l,r,rt);int mid=(l+r)>>1;if(nl<=mid)modify(lson,nl,nr,val);if(nr>mid)modify(rson,nl,nr,val);updata(rt);}T querySum(int l,int r,int rt,int nl,int nr){if(nl<=l&&nr>=r)return sum[rt];pushcol(l,r,rt);int mid=(l+r)>>1;T ans=0;if(nl<=mid)ans+=querySum(lson,nl,nr);if(nr>mid)ans+=querySum(rson,nl,nr);return ans;}T queryMx(int l,int r,int rt,int nl,int nr){if(nl<=l&&nr>=r)return Mx[rt].mv;pushcol(l,r,rt);int mid=(l+r)>>1;T ans=Mx->INF;if(nl<=mid)ans=max(ans,queryMx(lson,nl,nr));if(nr>mid)ans=max(ans,queryMx(rson,nl,nr));return ans;}T queryMn(int l,int r,int rt,int nl,int nr){if(nl<=l&&nr>=r)return Mn[rt].mv;pushcol(l,r,rt);int mid=(l+r)>>1;T ans=Mn->INF;if(nl<=mid)ans=min(ans,queryMn(lson,nl,nr));if(nr>mid)ans=min(ans,queryMn(rson,nl,nr));return ans;}#undef lson#undef rson
}
using namespace SegmentTreeBeats;
int main(){//  freopen("4695.in","r",stdin);//   freopen("4695.out","w",stdout);int n,m;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%lld",&v[i]);build(1,n,1);scanf("%d",&m);for(int i=1;i<=m;i++){int ck,l,r,val;scanf("%d%d%d",&ck,&l,&r);if(ck<=3)scanf("%d",&val);if(ck==1)modify(1,n,1,l,r,val);else if(ck==2)toMore(1,n,1,l,r,val);else if(ck==3)toLess(1,n,1,l,r,val);else if(ck==4)printf("%lld\n",querySum(1,n,1,l,r));else if(ck==5)printf("%lld\n",queryMx(1,n,1,l,r));else printf("%lld\n",queryMn(1,n,1,l,r));}
}

吉司机线段树(segment tree beats!)相关推荐

  1. BZOJ.4695.最假女选手(线段树 Segment tree Beats!)

    题目链接 区间取\(\max,\ \min\)并维护区间和是普通线段树无法处理的. 对于操作二,维护区间最小值\(mn\).最小值个数\(t\).严格次小值\(se\). 当\(mn\geq x\)时 ...

  2. 2020ICPC(南京) - Just Another Game of Stones(吉司机线段树+博弈)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的数列 aaa,现在需要执行 mmm 次操作,每次操作分为两种类型: 1lrx1 \ l \ r \ x1 l r x:对于所有 i∈[l,r]i ...

  3. HDU - 5306 Gorgeous Sequence(吉司机线段树)

    题目链接:点击查看 题目大意:给出 1 ~ n 的区间以及 m 次操作,每次操作分为三种形式: 0 l r val:对于区间 [ l , r ] ,a[ i ] = min ( a[ i ] , va ...

  4. 势能线段树(吉司机线段树)专题

    势能线段树(吉司机线段树)专题 势能线段树在近期训练时遇到了好几次,但是由于本人太懒一直没补完,结果ICPC网络赛还真就出了一道势能线段树Orz--结果当然是没做出来--痛定思痛,这回把之前欠的一块儿 ...

  5. 势能线段树/吉司机线段树-我没有脑子

    势能线段树/吉司机线段树 BZOJ3211 花神游历各国 BZOJ5312 冒险 BZOJ4355 Play with sequence BZOJ4695 最假女选手 \(A_i = max(A_i, ...

  6. P6242-[模板]线段树3【吉司机线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/P6242 题目大意 给出一个长度为nnn的序列aaa,mmm次要求支持操作 区间加上一个值kkk 区间所有aia_i ...

  7. P7560-[JOISC 2021 Day1]フードコート【吉司机线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/P7560 题目大意 有 n n n个队列,要求支持操作: 往 [ L , R ] [L,R] [L,R]的队列中插入 ...

  8. 2022.08.21 吉司机线段树略讲

    Interpretation \color{green}{\texttt{Interpretation}} Interpretation 吉司机线段树(A.K.A. 势能线段树),个人觉得,就是对普通 ...

  9. 线段树(Segment Tree)

    1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即"子数组"),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lgN). 线段树是一种二叉搜 ...

  10. Segment Tree Beats 区间最值问题

    Segment Tree Beats 区间最值问题 线段树一类特殊技巧! 引出:CF671C Ultimate Weirdness of an Array 其实是考试题,改题的时候并不会区间取最值,区 ...

最新文章

  1. AD域中NTP服务器的配置
  2. 5G URLLC — Overview
  3. 【Java】练习题:三角形法则
  4. 汇编 db,dw,dd
  5. Python安装第三方库太慢?配置好这个速度飞起
  6. LoadRunner 技巧之THML 与 URL两种录制模式分析
  7. Socket 之 API函数介绍
  8. java 队列 array_Java源码解析阻塞队列ArrayBlockingQueue常用方法
  9. A good book to learn C#2.0 ----C# 2.0 : Practical Guide for Programmers
  10. matlab图像基础处理小记
  11. three.js 坐标系、camera位置属性、点、线、面
  12. 1032. Sharing (25)-PAT甲级真题
  13. 互联网的长在线、心跳和断线重连
  14. 最新小浣熊5.0漫画CMS精仿土豪漫画系统源码
  15. 将python文件转成exe文件
  16. matlab英文界面翻译,Matlab最新的官方文档中文翻译
  17. 软件测试 等价类/边界值分析/随机数生成
  18. 爬虫基础篇之斗鱼弹幕
  19. hive on spark : 使用load data 命令将hdfs上数据覆写到hive表中报错:could not be cleaned up解决方法
  20. Java学习:从入门到精通week3

热门文章

  1. App低代码开发的最终形态?APICloud可视化开发初体验
  2. SPSS 25.0中文版安装教程【001期】
  3. Failed to read artifact descriptor for com.google.errorprone:javac:jar:9+181-r4173-1
  4. unity的UI元素层级调整的方法
  5. 计算机管理的显卡驱动,显卡驱动,教您显卡驱动怎么安装
  6. Android颜色透明度(不透明度)计算
  7. html网页综合项目实战
  8. Pr 音频效果参考:其它
  9. 应版权方要求,无法下载----替代迅雷的下载神器:EagleGet
  10. Ext.Net配色方案