Educational Codeforces Round 20 G. Periodic RMQ Problem(线段树+主席树)

本文提供了一种使用主席树和线段树解决CodeForces G题目的详细算法思路及实现代码,通过优化处理循环序列的更新和查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:http://codeforces.com/contest/803/problem/G


题解:

半夜三点闲来无事,激情刷题2333333


看到网上有dalao直接一颗线段树就搞定了。。。感觉自己白写了这么多啊?


其实考虑到整个序列是一个循环的,很容易想到会有很多的重复的状态,那么我们可以通过主席树来将所有的冗余状态合并起来进行维护。


更新操作可以拆分为,更新一整个周期的操作+更新周期的一部分的操作。对于更新一整个周期的操作,我们可以利用线段树区间更新最小值。对于局部的操作,可以直接在主席树上更新,然后将新的最小值插入到线段树上,注意,这类更新之前,我们要判断这个周期是否之前被操作过,相当于一个懒惰标记下放的过程。


查询的时候,也分为两种,覆盖一整个周期的+覆盖部分周期的,和更新类似,只要分类处理,下放懒惰标记就好了。。。


题目貌似不难,就是我写的太复杂了?还是菜啊。。。。


#include<bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
using namespace std;
const int MAXN=1e5+5;
const int M=MAXN*100;
const int SZ=1e4+5;
int n,q,tot,k,tot2;
int b[MAXN];
int T[MAXN/10],lson[M],rson[M],c[M],lazy[M],book[M],sv[M];
inline int getnode()
{
	int ret;
	if(tot2)
	{
		ret=sv[tot2--];
	}
	else
	{
		ret=tot++;
	}
	book[ret]++;
	lazy[ret]=rson[ret]=lson[ret]=c[ret]=0;
	return ret;
}
inline void del(int now)
{
	if(now==0)
		return ;
	book[now]--;
	if(!book[now])
	{
		sv[++tot2]=now;
	}
}
inline void push_up(int now)
{
	if(!lson[now]&&!rson[now])
		return ;
	c[now]=min(c[lson[now]],c[rson[now]]);
}
inline void push_down(int now)
{
	int newroot,root;
	if(lazy[now])
	{
		if(lson[now])
		{
			newroot=getnode();
			root=lson[now];
			lson[newroot]=lson[root];
			rson[newroot]=rson[root];
			del(root); 
			lson[now]=newroot;
			c[newroot]=lazy[now];
			lazy[newroot]=lazy[now];
		}
		if(rson[now])
		{
			newroot=getnode();
			root=rson[now];
			lson[newroot]=lson[root];
			rson[newroot]=rson[root];
			del(root);
			rson[now]=newroot;
			c[newroot]=lazy[now];
			lazy[newroot]=lazy[now];
		}
		lazy[now]=0;
	}
}
int build(int l,int r)
{
	int root=getnode();
	book[root]=k;
	if(l==r)
	{
		c[root]=b[l];
		return root;
	}
	int mid=(l+r)>>1;
	lson[root]=build(l,mid);
	rson[root]=build(mid+1,r);
	push_up(root);
	return root;
}
inline int update(int L,int R,int l,int r,int root,int val)
{
	int newroot=getnode();
	push_down(root);
	lson[newroot]=lson[root];
	rson[newroot]=rson[root];
	if(L<=l&&r<=R)
	{
		c[newroot]=val;
		lazy[newroot]=val;
		del(root);
		return newroot;
	}
	int mid=(l+r)>>1;
	if(L<=mid)
	{
		lson[newroot]=update(L,R,l,mid,lson[root],val);
	}
	if(R>mid)
	{
		rson[newroot]=update(L,R,mid+1,r,rson[root],val);
	}
	del(root);
	push_up(newroot);
	return newroot;
}
inline int query(int L,int R,int l,int r,int root)
{
	if(L<=l&&r<=R)
	{
		return c[root];
	}
	int mid=(l+r)>>1;
	push_down(root);
	int ret=1e9;
	if(L<=mid)
	{
		ret=min(ret,query(L,R,l,mid,lson[root]));
	}
	if(R>mid)
	{
		ret=min(ret,query(L,R,mid+1,r,rson[root]));
	}
	return ret;
}
struct segmentTree
{
	pair<int,int> tree[SZ<<2],lazy[SZ<<2];
	void push_up(int rt)
	{
		tree[rt]=min(tree[rt<<1],tree[rt<<1|1]);
	}
	void push_down(int rt)
	{
		if(lazy[rt].xx)
		{
			tree[rt<<1]=lazy[rt];
			tree[rt<<1|1]=lazy[rt];
			lazy[rt<<1]=lazy[rt];
			lazy[rt<<1|1]=lazy[rt];
			lazy[rt]=mp(0,0);
		}
	}
	void update(int L,int R,pair<int,int> val,int l,int r,int rt)
	{
		if(L>R)
			return ;
		if(L<=l&&r<=R)
		{
			tree[rt]=val;
			lazy[rt]=val;
			return ;
		}
		int mid=(l+r)>>1;
		push_down(rt);
		if(L<=mid)
		{
			update(L,R,val,l,mid,rt<<1);
		}
		if(R>mid)
		{
			update(L,R,val,mid+1,r,rt<<1|1);
		}
		push_up(rt);
	}
	pair<int,int> query(int pos,int l,int r,int rt)
	{
		if(l==r)
		{
			return tree[rt];
		}
		int mid=(l+r)>>1;
		push_down(rt);
		if(pos<=mid)
			return query(pos,l,mid,rt<<1);
		if(pos>mid)
			return query(pos,mid+1,r,rt<<1|1);
	}
	int querymin(int L,int R,int l,int r,int rt)
	{
		if(L>R)
			return 1e9;
		if(L<=l&&r<=R)
		{
			return tree[rt].xx;
		}
		int mid=(l+r)>>1;
		int ret=1e9;
		push_down(rt);
		if(L<=mid)
			ret=min(ret,querymin(L,R,l,mid,rt<<1));
		if(R>mid)
			ret=min(ret,querymin(L,R,mid+1,r,rt<<1|1));
		return ret;
	}
}se;
int main()
{
	//freopen("in.txt","r",stdin); 
	//freopen("out.txt","w",stdout); 
	tot=1;c[0]=1e9;tot2=0;
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&b[i]);
	}
	T[0]=build(0,n-1);
	se.update(0,0,mp(c[T[0]],0),0,k-1,1);
	for(int i=1;i<k;i++)
	{
		T[i]=T[0];
		se.update(i,i,mp(c[T[i]],0),0,k-1,1);
	}
	scanf("%d",&q);
	while(q--)
	{
		int op;
		scanf("%d",&op);
		if(op==1)
		{
			int l,r,x,L,R;
			scanf("%d%d%d",&l,&r,&x);
			l--,r--;
			L=l/n;R=r/n;
			se.update(L+1,R-1,mp(x,1),0,k-1,1);
			int ll,rr;
			ll=l%n;rr=r%n;
			pair<int,int> pii;
			if(L==R)
			{
				pii=se.query(L,0,k-1,1);
				if(pii.yy)
				{
					T[L]=update(0,n-1,0,n-1,T[L],pii.xx);
				}
				T[L]=update(ll,rr,0,n-1,T[L],x);
				se.update(L,L,mp(c[T[L]],0),0,k-1,1);
			}
			else
			{
				pii=se.query(L,0,k-1,1);
				if(pii.yy)
				{
					T[L]=update(0,n-1,0,n-1,T[L],pii.xx);
				}
				T[L]=update(ll,n-1,0,n-1,T[L],x);
				se.update(L,L,mp(c[T[L]],0),0,k-1,1);
				pii=se.query(R,0,k-1,1);
				if(pii.yy)
				{
					T[R]=update(0,n-1,0,n-1,T[R],pii.xx);
				}
				T[R]=update(0,rr,0,n-1,T[R],x);
				se.update(R,R,mp(c[T[R]],0),0,k-1,1);
			}
		}
		if(op==2)
		{
			int l,r,L,R,ans=1e9;
			scanf("%d%d",&l,&r);
			l--,r--;
			L=l/n;R=r/n;
			ans=min(ans,se.querymin(L+1,R-1,0,k-1,1));
			int ll,rr;
			ll=l%n;rr=r%n;
			pair<int,int> pii;
			if(L==R)
			{
				pii=se.query(L,0,k-1,1);
				if(pii.yy)
				{
					T[L]=update(0,n-1,0,n-1,T[L],pii.xx);
				}
				ans=min(ans,query(ll,rr,0,n-1,T[L]));
				if(pii.yy)
				{
					se.update(L,L,mp(c[T[L]],0),0,k-1,1);
				}
			}
			else
			{
				pii=se.query(L,0,k-1,1);
				if(pii.yy)
				{
					T[L]=update(0,n-1,0,n-1,T[L],pii.xx);
				}
				ans=min(ans,query(ll,n-1,0,n-1,T[L]));
				if(pii.yy)
				{
					se.update(L,L,mp(c[T[L]],0),0,k-1,1);
				}
				pii=se.query(R,0,k-1,1);
				if(pii.yy)
				{
					T[R]=update(0,n-1,0,n-1,T[R],pii.xx);
				}
				ans=min(ans,query(0,rr,0,n-1,T[R]));
				if(pii.yy)
				{
					se.update(R,R,mp(c[T[R]],0),0,k-1,1);
				}
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}


### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置和速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线段交集判断和平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类和辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值