首页 > 其他分享 >GSS系列

GSS系列

时间:2023-03-21 12:45:02浏览次数:41  
标签:GSS 系列 rr int ll mid return root

最近在做GSS系列,都是数据结构非常好的题,正适合本蒟蒻练习qwq

GSS1

最大子段和的经典题,区间的最大子段和考虑到三种情况,左区间的最大前缀,右区间的最大后缀,左区间最大后缀和右区间最大前缀拼接而成

不难想到用线段树记录区间最大前缀和prefix,区间最大后缀和suffix,区间最大子段和ans,再记录一下区间和sum来维护前缀后缀即可

ps:用结构体的方式写会简便很多,可以再用重载运算符来处理区间合并,码量会降不少www

my code
#include<bits/stdc++.h>
#define lson (root<<1)
#define rson (root<<1|1)
using namespace std;
const int N=5e4+10;
int n,m,a[N];
#define seg segment_tree
struct segment_tree{
	int l,r,ans,sum,prefix,suffix;
	inline void init(int x){
		l=r=x;
		ans=sum=prefix=suffix=a[x];
	}
	friend seg operator + (const seg &ls,const seg &rs){
		seg rt;
		rt.l=ls.l,rt.r=rs.r;
		rt.sum=ls.sum+rs.sum;
		rt.prefix=max(ls.prefix,ls.sum+rs.prefix);
		rt.suffix=max(rs.suffix,rs.sum+ls.suffix);
		rt.ans=max({ls.ans,rs.ans,ls.suffix+rs.prefix});
		return rt;
	} 
}tr[N<<2];

inline void File(){
	freopen("GSS1.in","r",stdin);
	freopen("GSS1.out","w",stdout);
} 
 
inline void push_up(int root){
	tr[root]=tr[lson]+tr[rson];
}

inline void build(int root,int ll,int rr){
	if(ll==rr){
		tr[root].init(ll);
		return;
	}
	int mid=(ll+rr)>>1;
	build(lson,ll,mid);
	build(rson,mid+1,rr);
	push_up(root);
} 
#define l(x) tr[x].l
#define r(x) tr[x].r
inline segment_tree query(int root,int ll,int rr){
	if(ll<=l(root)&&rr>=r(root)){
		return tr[root];
	}	
	int mid=(l(root)+r(root))>>1;
	if(ll<=mid&&rr>mid){				
		return query(lson,ll,rr)+query(rson,ll,rr);	
	}
	else{	
		if(ll<=mid)return query(lson,ll,rr);
		if(rr>mid)return query(rson,ll,rr);
	}	
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",a+i);
	}	
	build(1,1,n);
	scanf("%d",&m);
	while(m--){
		int l,r;
		scanf("%d%d",&l,&r);	
		printf("%d\n",query(1,l,r).ans);
	}
	return 0;
}

GSS3

同理GSS1,加上单点修改操作即可

my code
#include<bits/stdc++.h>
#define lson (root<<1)
#define rson (root<<1|1)
using namespace std;
const int N=5e4+10;
int n,m,a[N];
#define seg segment_tree
struct segment_tree{
	int l,r,ans,sum,prefix,suffix;
	inline void init(int x){
		ans=sum=prefix=suffix=x;
	}
	friend seg operator + (const seg &ls,const seg &rs){
		seg rt;
		rt.l=ls.l,rt.r=rs.r;
		rt.sum=ls.sum+rs.sum;
		rt.prefix=max(ls.prefix,ls.sum+rs.prefix);
		rt.suffix=max(rs.suffix,rs.sum+ls.suffix);
		rt.ans=max({ls.ans,rs.ans,ls.suffix+rs.prefix});
		return rt;
	} 
}tr[N<<2];

inline void File(){
	freopen("GSS3.in","r",stdin);
	freopen("GSS3.out","w",stdout);
} 
#define l(x) tr[x].l
#define r(x) tr[x].r
inline void push_up(int root){
	tr[root]=tr[lson]+tr[rson];
}

inline void build(int root,int ll,int rr){
	l(root)=ll,r(root)=rr;
	if(ll==rr){
		tr[root].init(a[ll]);
		return;
	}
	int mid=ll+rr>>1;
	build(lson,ll,mid);
	build(rson,mid+1,rr);
	push_up(root);
} 

inline void modify(int root,int x,int val){
	if(l(root)==r(root)){
		tr[root].init(val);
		return;
	}
	int mid=l(root)+r(root)>>1;
	if(x<=mid)modify(lson,x,val);
	else modify(rson,x,val);
	push_up(root);
}

inline segment_tree query(int root,int ll,int rr){
	if(ll<=l(root)&&rr>=r(root)){
		return tr[root];
	}	
	int mid=l(root)+r(root)>>1;
	if(ll<=mid&&rr>mid){				
		return query(lson,ll,rr)+query(rson,ll,rr);	
	}
	else{	
		if(ll<=mid)return query(lson,ll,rr);
		if(rr>mid)return query(rson,ll,rr);
	}	
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",a+i);
	}	
	build(1,1,n);
	scanf("%d",&m);
	int opt,l,r;
	while(m--){
		scanf("%d",&opt);
		switch(opt){
			case 0:
				scanf("%d%d",&l,&r);
				modify(1,l,r);
				break;
			case 1:				
				scanf("%d%d",&l,&r);	
				printf("%d\n",query(1,l,r).ans);
				break;
		}
	}
	return 0;
}

GSS4

看到了这题,我突然联想到了数列分块入门5,不觉得这两题有异曲同工之妙吗?(好吧其实就相当于一道题)

于是用分块打了,因为一个(正)数多次开方后的结果必定为1,(如果有0的话那就是0)

那么我们就把块中结果全是1或0的打上标记,下次修改的时候直接跳过即可,对于其他的情况就暴力开方修改

结果T掉了,换上了快读才AC,还是我太弱了qwq

my code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
inline long long read(){
	long long x=0;char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x;
}
inline void File(){
	freopen("GSS4.in","r",stdin);
	freopen("GSS4.out","w",stdout);
} 
bool tag[N];
int n,t;
long long a[N],L[N],R[N],pos[N],sum[N];
inline void pre_work(){
	t=sqrt(n);
	for(int i=1;i<=n;++i) L[i]=(i-1)*t+1,R[i]=i*t;
	if(R[t]<n){t++;L[t]=R[t-1]+1;R[t]=n;}
	for(int i=1;i<=t;++i)
		for(int j=L[i];j<=R[i];++j)
			pos[j]=i,sum[i]+=a[j];
} 

inline void update(int x){
	tag[x]=true;
	for(int i=L[x];i<=R[x];++i){
		sum[x]-=a[i];
		a[i]=sqrt(a[i]);
		sum[x]+=a[i];
		if(a[i]>1)tag[x]=false;
	}
}

inline void change(int l,int r){
	if(pos[l]==pos[r]){		
		for(int i=l;i<=r;++i){
			sum[pos[l]]-=a[i];
			a[i]=sqrt(a[i]);
			sum[pos[l]]+=a[i];
		}
	}
	else{
		for(int i=pos[l]+1;i<=pos[r]-1;++i) if(!tag[i]) update(i);
		for(int i=l;i<=R[pos[l]];++i){
			sum[pos[l]]-=a[i];
			a[i]=sqrt(a[i]);
			sum[pos[l]]+=a[i];
		}
		for(int i=L[pos[r]];i<=r;++i){
			sum[pos[r]]-=a[i];
			a[i]=sqrt(a[i]);
			sum[pos[r]]+=a[i];
		}
	}
}

inline void ask(int l,int r){
	long long ans=0;
	if(pos[l]==pos[r]){
		for(int i=l;i<=r;++i) ans+=a[i]; 
	}
	else{
		for(int i=pos[l]+1;i<=pos[r]-1;++i) ans+=sum[i];
		for(int i=l;i<=R[pos[l]];++i) ans+=a[i];
		for(int i=L[pos[r]];i<=r;++i) ans+=a[i];
	}
	printf("%lld\n",ans);
}
int main(){
	for(int T=1,opt,l,r,c,m;(~scanf("%d",&n));++T){		
		memset(tag,0,sizeof(tag));
		memset(sum,0,sizeof(sum));
		for(int i=1;i<=n;++i)a[i]=read(); pre_work();
		m=read();
		printf("Case #%d:\n",T);
		for(int i=1;i<=m;++i){
			opt=read();l=read();r=read(); if(l>r) swap(l,r);
			if(opt) ask(l,r);
			else change(l,r);
		}	
		printf("\n");		
	}
	return 0;
} 

之后又调了一个线段树版本的,思路同理分块,遇到全为0/1的区间就跳过,会比分块快很多qaq

my code
#include<bits/stdc++.h>
#define lson (root<<1)
#define rson (root<<1|1)
inline long long read(){
	long long x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x;
}

using namespace std;
const int N=1e5+10;
int n,m;
long long a[N];
struct segment_tree{
	int l,r;long long sum;bool tag;
	inline void check(long long x){
		sum=x;
		if(sum<=1)tag=true;
		else tag=false;
	}
	#define l(x) tr[x].l
	#define r(x) tr[x].r
	#define sum(x) tr[x].sum
	#define tag(x) tr[x].tag
}tr[N<<2];

inline void File(){
	freopen("GSS4.in","r",stdin);
	freopen("GSS4.out","w",stdout);
} 

inline void push_up(int root){
	sum(root)=sum(lson)+sum(rson);
	tag(root)=(tag(lson)&&tag(rson));
}

inline void build(int root,int ll,int rr){
	l(root)=ll,r(root)=rr;
	if(l(root)==r(root)){
		tr[root].check(a[ll]);
		return;
	}
	int mid=ll+rr>>1;
	build(lson,ll,mid);
	build(rson,mid+1,rr);
	push_up(root);
} 

inline void modify(int root,int ll,int rr){
	if(tag(root))return;
	if(l(root)==r(root)){
		tr[root].check(sqrt(sum(root)));
		return;
	}
	int mid=l(root)+r(root)>>1;
	if(ll<=mid)modify(lson,ll,rr);
	if(rr>mid) modify(rson,ll,rr);
	push_up(root);
}

inline long long query(int root,int ll,int rr){
	if(ll<=l(root)&&rr>=r(root)){
		return sum(root);
	}	
	int mid=l(root)+r(root)>>1;
	long long ans=0;
	if(ll<=mid)ans+=query(lson,ll,rr);
	if(rr>mid)ans+=query(rson,ll,rr);
	return ans;
}

int main(){
	for(int T=1,m;(~scanf("%d",&n));++T){
		printf("Case #%d:\n",T);
		memset(a,0,sizeof(a));memset(tr,0,sizeof(tr));
		for(int i=1;i<=n;++i) a[i]=read(); 
		build(1,1,n);
		m=read();
		for(int i=1,opt,l,r;i<=m;++i){
			opt=read();l=read();r=read(); if(l>r) swap(l,r);
			if(opt) printf("%lld\n",query(1,l,r));
			else modify(1,l,r);	
		}
		printf("\n");
	}
	return 0;
}

标签:GSS,系列,rr,int,ll,mid,return,root
From: https://www.cnblogs.com/Flandre495/p/17207122.html

相关文章

  • 《全链路压测从零开始》系列
    转载:https://www.cnblogs.com/imyalost/p/16320776.html全链路压测相关的技术文章,零零碎碎写了蛮多的。去年9月份开始,写下了全链路压测系列的第一篇文章,直到今天终于完结......
  • 自己动手从零写桌面操作系统GrapeOS系列教程——20.汇编语言读硬盘实战
    学习操作系统原理最好的方法是自己写一个简单的操作系统。本讲我们设计一个简单的读硬盘实验。通过一定的方法使硬盘第二个扇区的前3个字节依次为1、2、3,最后3个字节依......
  • Spring Cloud Alibaba系列(一)限流与防护组件Sentinel的简单使用
    Sentinel是SpringCloudAlibaba体系的安全防护组件,我们可以使用它以“非业务侵入”方式实现限流,熔断,服务降级需求。一.下载并启动Sentinel控制台从GitHub网址https......
  • “性能续航小超人”iQOO Z7系列登场:售价仅1299元起
    2023年3月20日,“性能续航小超人”iQOOZ7系列正式发布,带来同价位领先的闪充大电池体验,并具备出色的游戏性能体验以及全方位的功能配置,普及领先科技体验,带给对注重产品品质和......
  • 每天上一当系列之vue修饰符.number
    今天使用number修饰符去处理el-input的内容为数字做校验原本以为省事不少,没想到,为0开头无法输入第二位以后,并且输入的比较多的时候会出现Infinity很神奇,网上查了说是eleme......
  • 一天一个小技巧系列
    每天上一当,当当不一样大家好,今天说一下可选链1.obj?.prop.--------如果obj存在则返回obj.prop,否则返回undefined。2.obj?.[prop]-------如果存在则返回obj[pro......
  • 全志系列芯片如何在Tina Linux中使用脚本完成定制化升级?
    1.主题在TinaLinux中,如何使用脚本完成定制化升级2.问题背景硬件:全平台软件:Tina其他:支持OTA升级的平台,可实现脚本定制化升级3.具体表现在OTA升级过程中,添加定制化需......
  • webgl 系列 —— 绘制猫
    其他章节请看:webgl系列绘制猫上文我们了解了如何绘制渐变彩色三角形,明白了图形装配、光栅化,以及片元着色器计算片元的颜色。现在如果让你绘制如下一只猫。难道绘制......
  • Spider理论系列--协程(二)
    aiohttp与aiofiles1、安装与使用pipinstallaiohttp2、简单实例使用aiohttp的自我介绍中就包含了客户端和服务器端,所以我们分别来看下客户端和服务器端的简单实例代码。客......
  • 测试公开课资料系列03--Jmeter之关联实现&参数化应用
     前言当你变的优秀时,你想要的都会来找你。一、Jmeter介绍1.一款融合接口、性能都能完成的测试工具2.纯JAVA开发的工具3.开源工具4.支持多种协议5......