F. Raging Thunder 线段树 + 区间合并
时间:2020-07-10
本文章向大家介绍F. Raging Thunder 线段树 + 区间合并,主要包括F. Raging Thunder 线段树 + 区间合并使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
先感叹一句,这个题目真变态,我写了五六个小时。。。。。而且还是在知道怎么写的情况下。。。
题目大意:
给你一个字符串,这个字符串只包含 \(>\) 和 \(<\) ,其中 \(>\) 表示该位置的球会向右滚一格, \(<\) 表示该位置的球会向左滚一格,如果最左边是 \(<\) 则表示球会落到位置为0的这个洞里,如果最右边是 \(>\) 则表示球会落到位置为 \(n+1\) 的这个洞里。一共有 \(m\) 次询问,每次询问给你一个区间 \([l,r]\) ,表示这个区间的所有的字符会反向,即 \(>\) 变成 \(<\) ,\(<\) 变成 \(>\) ,而且这个区间每个位置会落下一颗球,找出一个洞中最大的球的数量,提示:每一次询问之后,字符的改变会保留。
题解:
- 先把这个字符串转化成01字符串,\(>\) 表示1,\(<\) 表示0,这个题目就转化成求最长的1...0...字符串
- 然后你会发现我们要求的字符串就类似于 00111000111,起始是01,结束也是01,结果转化为求间隔最远的01。
- 第三步就是把01,00,10,11进行转化以便于求间隔最远的01
- 把00转化为2,01转化为0,10转化为3,11转化为1
- 最后需要维护的有最长的0的间隔,最长的3的间隔,最左边的0、3,最右边的0、3
- 对于一个区间进行更新,容易得到就是把0换成了3,1换成了2
- 例如:000111 那么转化后 22011,对这整个区间进行更新则变成111000,转化后11322
- 但是要注意的是更新一个区间,其左右端点需要单独更新,这个可以自己想清楚
这个是我写之前就知道了的,之后写的过程中写出来很多的bug
- 求解需要一个区间合并
- 区间合并的时候要注意限制在求的范围内
- 还有一些写在代码里面了
这个题目的转化挺难想的,也很考验码力,和区间合并的线段树很像
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
#define debug(x) printf("debug:%s=%d\n",#x,x);
//#define debug(x) cout << #x << ": " << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn =5e5+10;
int lc0[maxn*4],lc3[maxn*4],rc0[maxn*4],rc3[maxn*4];
int len0[maxn*4],len3[maxn*4],a[maxn],lazy[maxn*4];
char s[maxn];
void push_up(int id){
lc0[id]=min(lc0[id<<1],lc0[id<<1|1]);
lc3[id]=min(lc3[id<<1],lc3[id<<1|1]);
rc0[id]=max(rc0[id<<1],rc0[id<<1|1]);
rc3[id]=max(rc3[id<<1],rc3[id<<1|1]);
len0[id]=max(len0[id<<1],len0[id<<1|1]);
len3[id]=max(len3[id<<1],len3[id<<1|1]);
if(lc0[id<<1|1]!=inf&&rc0[id<<1]!=0) len0[id]=max(len0[id],lc0[id<<1|1]-rc0[id<<1]);
if(lc3[id<<1|1]!=inf&&rc3[id<<1]!=0) len3[id]=max(len3[id],lc3[id<<1|1]-rc3[id<<1]);
// printf("lec0[%d]=%d\n",id,len0[id]);
// printf("l len=%d r len=%d\n",len0[id<<1],len0[id<<1|1]);
// printf("lc0[%d]=%d rc[%d]=%d\n",id<<1|1,lc0[id<<1|1],id<<1,rc0[id<<1]);
}
void build(int id,int l,int r){
if(l==r){
if(a[l]==0) lc0[id]=l,rc0[id]=l;
if(a[l]==3) lc3[id]=l,rc3[id]=l;
return ;
}
int mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
push_up(id);
}
void change(int id,int l,int r){
//如果是叶子节点,则直接更新即可,不需要进行swap
if(l==r) {
a[l]=3-a[l];
//无论这个位置是什么都要注意状态的更新,是0,则也要更新3的状态
if(a[l]==0) lc0[id]=l,rc0[id]=l,lc3[id]=inf,rc3[id]=0;
else if(a[l]==3) lc3[id]=l,rc3[id]=l,lc0[id]=inf,rc0[id]=0;
else lc0[id]=inf,lc3[id]=inf,rc0[id]=0,rc3[id]=0;
// printf("a[%d]=%d id=%d l=%d r=%d\n",l,a[l],id,lc0[id],rc0[id]);
}
else{
lazy[id]^=1;
swap(len0[id],len3[id]);
swap(lc0[id],lc3[id]);
swap(rc0[id],rc3[id]);
}
}
void push_down(int id,int l,int r){
// printf("id=%d l=%d r=%d lazy=%d\n",id,l,r,lazy[id]);
if(lazy[id]==0) return ;
int mid=(l+r)>>1;
change(id<<1,l,mid);
change(id<<1|1,mid+1,r);
lazy[id]=0;
}
void update(int id,int l,int r,int x,int y){
// printf("update id=%d l=%d r=%d x=%d y=%d\n",id,l,r,x,y);
if(x>r||y<l) return ;
if(x<=l&&y>=r){
change(id,l,r);
// printf("updatein lc0[%d]=%d rc0[%d]=%d a[%d]=%d\n",id,lc0[id],id,rc0[id],l,a[l]);
return ;
}
push_down(id,l,r);
int mid=(l+r)>>1;
if(x<=mid) update(id<<1,l,mid,x,y);
if(y>mid) update(id<<1|1,mid+1,r,x,y);
push_up(id);
}
int query(int id,int l,int r,int x,int y){
if(x<=l&&y>=r) return len0[id];
// printf("ans1 id=%d l=%d r=%d x=%d y=%d\n",id,l,r,x,y);
int mid=(l+r)>>1,ans=0;
push_down(id,l,r);
//区间合并
if(y<=mid) return query(id<<1,l,mid,x,y);
else if(x>mid) return query(id<<1|1,mid+1,r,x,y);
else{
int ans1 =query(id<<1,l,mid,x,y);
int ans2 =query(id<<1|1,mid+1,r,x,y);
int ans3 =0;
if(lc0[id<<1|1]!=inf&&rc0[id<<1]!=0) ans3 = min(y,lc0[id<<1|1])-max(rc0[id<<1],x);
//在min(y,lc0[id<<1|1]) max(x,rc0[id<<1]) 这个是因为求的范围是 x y,但是这个位置可能大于y或者小于x,所以这里要做一个限制
// printf("id=%d ans1=%d ans2=%d ans3=%d\n",id,ans1,ans2,ans3);
return max(ans1,max(ans2,ans3));
}
}
int querylc(int id,int l,int r,int x,int y){
if(x<=l&&y>=r) return lc0[id];
int mid=(l+r)>>1,ans=inf;
// printf("ans2 id=%d\n",id);
push_down(id,l,r);
if(x<=mid) ans=min(ans,querylc(id<<1,l,mid,x,y));
if(y>mid) ans=min(ans,querylc(id<<1|1,mid+1,r,x,y));
return ans;
}
int queryrc(int id,int l,int r,int x,int y){
if(x<=l&&y>=r) return rc0[id];
int mid=(l+r)>>1,ans=0;
// printf("ans3 id=%d\n",id);
push_down(id,l,r);
if(x<=mid) ans=max(ans,queryrc(id<<1,l,mid,x,y));
if(y>mid) ans=max(ans,queryrc(id<<1|1,mid+1,r,x,y));
return ans;
}
void modify(int id,int l,int r,int pos,int f){
if(l==r){
// printf("before f=%d a[%d]=%d\n",f,l,a[l]);
//无论这个位置是什么都要注意状态的更新,是0,则也要更新3的状态
if(f==1){
if(a[l]==3) a[l]=1,lc3[id]=inf,rc3[id]=0;
else if(a[l]==1) a[l]=3,lc3[id]=l,rc3[id]=l;
else if(a[l]==0) a[l]=2,lc0[id]=inf,rc0[id]=0;
else if(a[l]==2) a[l]=0,lc0[id]=l,rc0[id]=r;
}
else{
if(a[l]==3) a[l]=2,lc3[id]=inf,rc3[id]=0;
else if(a[l]==2) a[l]=3,lc3[id]=l,rc3[id]=l;
else if(a[l]==0) a[l]=1,lc0[id]=inf,rc0[id]=0;
else if(a[l]==1) a[l]=0,lc0[id]=l,rc0[id]=r;
}
// printf("f=%d a[%d]=%d\n",f,l,a[l]);
return ;
}
// printf("ss id=%d l=%d r=%d\n",id,l,r);
int mid=(l+r)>>1;
push_down(id,l,r);
if(pos<=mid) modify(id<<1,l,mid,pos,f);
if(pos>mid) modify(id<<1|1,mid+1,r,pos,f);
push_up(id);
}
void push_alldown(int id,int l,int r){
if(l==r) return ;
// printf("id=%d ddd\n",id);
push_down(id,l,r);
int mid=(l+r)>>1;
push_alldown(id<<1,l,mid);
push_alldown(id<<1|1,mid+1,r);
}
void print(int n){
for(int i=1;i<=n;i++) printf("a[%d]=%d\t",i,a[i]);
printf("\n");
}
int main(){
int n,m;
memset(lc0,inf,sizeof(lc0));
memset(lc3,inf,sizeof(lc3));
scanf("%d%d",&n,&m);
scanf("%s",s+1);
if(n==1){
while(m--) printf("%d\n",1);
return 0;
}
for(int i=1;i<n;i++){
if(s[i]=='>'&&s[i+1]=='<') a[i]=3;
if(s[i]=='<'&&s[i+1]=='>') a[i]=0;
if(s[i]=='>'&&s[i+1]=='>') a[i]=1;
if(s[i]=='<'&&s[i+1]=='<') a[i]=2;
}
build(1,1,n-1);
// print(n-1);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
update(1,1,n-1,x,y-1);
if(x>1) modify(1,1,n-1,x-1,1);
if(y<n) modify(1,1,n-1,y,2);
// printf("xxx\n");
// push_alldown(1,1,n-1);
// print(n-1);
if(x==y){
printf("1\n");
continue;
}
int ans=query(1,1,n-1,x,y-1);
int lc=querylc(1,1,n-1,x,y-1);
int rc=queryrc(1,1,n-1,x,y-1);
// printf("\n\n");
if(rc==0) printf("%d\n",y-x+1);
else{
// printf("lc=%d rc=%d ans=%d\n",lc,rc,ans);
ans=max(ans,max(y-rc,lc-x+1));
printf("%d\n",ans);
}
}
}
原文地址:https://www.cnblogs.com/EchoZQN/p/13281087.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 静态链表
- 中流砥柱java的动态代理
- java的反射机制到底是做什么的?
- Java中是否直接可以使用enum进行传输
- PHP 恶意程序简单分析
- springboot之相关环境设置
- springboot之第一个springboot程序
- 「查缺补漏」巩固你的RocketMQ知识体系
- springboot之场景启动器
- ICLR2020 | 深度自适应Transformer
- springboot之自动配置
- golang--连接redis数据库并进行增删查改
- golang--redis连接池
- springboot配置之使用application.properties时编码问题
- mybatis动态sql之foreach补充(二)