【日记】12.6
12.6日记
线段树
- HDU1540:单点修改+单点所在最长连续区间
思路:昨天用了set(平衡树)做的,发现简单的一批,还是学了一下线段树的做法。不过学完了之后发现,确实用线段树还是很有必要的,如果是区间修改的话,平衡树就挂了,就只能用线段树来处理了。更何况还有可能有区间所在最长连续区间之类的题目。
构造:每个节点存放4个值,lm记录当前区间,以左端点为左端点的最长1区间的长度,rm记录当前区间,以右端点为右端点的最长1区间的长度,mm记录当前区间最长1区间的长度,col是辅助数组,如果当前区间全都是1,那么col=1,如果当前区间全都是0,那么col=0,否则col=-1。显然col可以直接用mm来代替,所以简单写的话存放3个值就可以。
pushup:(核心操作)
- lm:如果左儿子全为1,则lm[id]=lm[id*2]+lm[id*2+1](因为会扩展到右区间),否则lm[id]=lm[id*2]
- rm:如果右儿子全为1,则rm[id]=rm[id*2]+rm[id*2+1](因为会扩展到右区间),否则rm[id]=rm[id*2+1]
- mm:三个值的最大值:mm[id]=max(mm[id*2],mm[id*2+1],rm[id*2]+lm[id*2+1])
- col:用mm的值去推。如果mm=0则col=0,如果mm=r-l+1则col=1,否则col=-1。
此处没有pushdown操作。
operate:直接暴力单点修改,记得pushup
query:比较复杂。核心思想是:检验目标点是否可以被横跨两个儿子的区间所包含,如果能,就直接求得答案,否则递归。
具体实现如下,首先判断目标点pos在左儿子还是右儿子。如果在左儿子,那么判断rm[id*2]是否可能包含pos,如果能包含,则return rm[id*2]+lm[id*2+1]。否则就递归左儿子。如果在右儿子,那么判断lm[id*2+1]是否可能包含pos,如果能包含,则return rm[id*2]+lm[id*2+1]。否则就递归右儿子。
用贪心容易知道,如果能包含的话,直接返回的长度,就是最长的区间。
#include<bits/stdc++.h>
#define mid (l+r)/2
using namespace std;
const int M=5e4+20;
int lm[4*M],rm[4*M],mm[4*M],col[4*M];
inline void pushup(int id,int l,int r){
if (col[id*2]==1)
lm[id]=lm[id*2]+lm[id*2+1];
else
lm[id]=lm[id*2];
if (col[id*2+1]==1)
rm[id]=rm[id*2+1]+rm[id*2];
else
rm[id]=rm[id*2+1];
mm[id]=max(max(mm[id*2],mm[id*2+1]),rm[id*2]+lm[id*2+1]);
if (mm[id]==0)
col[id]=0;
else if (mm[id]==r-l+1)
col[id]=1;
else
col[id]=-1;
}
void build(int id,int l,int r){
col[id]=1;
lm[id]=rm[id]=mm[id]=r-l+1;
if (l==r)
return;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
pushup(id,l,r);
}
void operate(int id,int l,int r,int pos,int x){
if (l==r){
if (x)
lm[id]=rm[id]=mm[id]=col[id]=1;
else
lm[id]=rm[id]=mm[id]=col[id]=0;
return;
}
if(pos<=mid)
operate(id*2,l,mid,pos,x);
else
operate(id*2+1,mid+1,r,pos,x);
pushup(id,l,r);
}
int query(int id,int l,int r,int pos){
if(l==r)
return mm[id];
if (pos<=mid){
if (pos+rm[id*2]>mid)
return rm[id*2]+lm[id*2+1];
else
return query(id*2,l,mid,pos);
}
else{
if (mid+lm[id*2+1]>=pos)
return rm[id*2]+lm[id*2+1];
else
return query(id*2+1,mid+1,r,pos);
}
}
stack<int> stk;
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
build(1,1,n);
for(int i=1;i<=m;++i){
char s[2];
int x;
scanf("%s",s);
if (s[0]=='R')
operate(1,1,n,stk.top(),1),stk.pop();
else{
scanf("%d",&x);
if (s[0]=='D')
operate(1,1,n,x,0),stk.push(x);
else
printf("%d\n",query(1,1,n,x));
}
}
}
return 0;
}
总结
最近实在是太忙了,我哭了,赶紧学习。还有一个周,拼了!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥