IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> CF1039E-Summer Oenothera Exhibition【LCT根号分治】 -> 正文阅读

[数据结构与算法]CF1039E-Summer Oenothera Exhibition【LCT根号分治】

正题

题目链接:https://www.luogu.com.cn/problem/CF1039E


题目大意

给出 n n n个数的序列, m m m次询问至少将这个序列分成多少段才能满足每一段的和不超过 w ? q i w-q_i w?qi?

1 ≤ n , m ≤ 1 0 5 , 1 ≤ w , a i ≤ 1 0 9 1\leq n,m\leq 10^5,1\leq w,a_i\leq 10^9 1n,m105,1w,ai?109


解题思路

考虑暴力的做法,我们可以每次走到必须要分段时才分段显然是正确的。

根据 w ? q i w-q_i w?qi?从小到大来做,设 t i t_i ti?表示以 i i i为左端点时,最长能分到的区间长度 t i t_i ti?,那么我们从 i i i就能直接到达 i + t i i+t_i i+ti?

那么我们从 1 1 1出发一直往右跳看跳的次数就可以了,这个和[HNOI2010]弹飞绵羊很像,考虑用 L C T LCT LCT去维护。

不过这个 t i t_i ti?是可能每次都在改变的,所以不能只靠这样来做,但是注意到 i i i每次会直接跳过 t i ? 1 t_i-1 ti??1个位置,我们不需要统计全局的值。

所以我们考虑根号分治,对于一个 T = n T=\sqrt n T=n ?,我们当 t i ≤ T t_i\leq T ti?T时我们在 L C T LCT LCT上条,当 t i > T t_i>T ti?>T时我们直接暴力跳。

同样的我们不需要去维护这些 > T >T >T t i t_i ti?,而是到达这些位置时直接二分下一个位置即可。

用一个堆去存 t i ≤ T t_i\leq T ti?T的位置以方便更改。

时间复杂度: O ( n n log ? n ) O(n\sqrt n\log n) O(nn ?logn)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath> 
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=1e5+10,Q=230;
int n,m,w,a[N],t[N],ans[N];
int f[N][19],g[N][19],lg[N];
pair<int,int> q[N];
priority_queue<pair<int,int> >h;
struct LCT{
	int t[N][2],siz[N],fa[N];
	stack<int> s;bool r[N];
	bool Nroot(int x)
	{return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}
	bool Direct(int x)
	{return (t[fa[x]][1]==x);}
	void PushUp(int x)
	{siz[x]=siz[t[x][0]]+siz[t[x][1]]+1;return;}
	void PushR(int x){swap(t[x][0],t[x][1]);r[x]^=1;return;}
	void PushDown(int x){
		if(r[x]){
			PushR(t[x][0]);
			PushR(t[x][1]);
			r[x]=0;
		}
		return;
	}
	void Rotate(int x){
		int y=fa[x],z=fa[y];
		int xs=Direct(x),ys=Direct(y);
		int w=t[x][xs^1];
		t[x][xs^1]=y;t[y][xs]=w;
		if(Nroot(y))t[z][ys]=x;
		if(w)fa[w]=y;fa[y]=x;fa[x]=z;
		PushUp(y);PushUp(x);return;
	}
	void Splay(int x){
		int y=x;s.push(y);
		while(Nroot(y))y=fa[y],s.push(y);
		while(!s.empty())PushDown(s.top()),s.pop();
		while(Nroot(x)){
			int y=fa[x];
			if(!Nroot(y))Rotate(x);
			else if(Direct(x)==Direct(y))
				Rotate(y),Rotate(x);
			else Rotate(x),Rotate(x);
		}
		return;
	}
	void Access(int x){
		for(int y=0;x;y=x,x=fa[x])
			Splay(x),t[x][1]=y,PushUp(x);
		return;
	}
	void MakeRoot(int x)
	{Access(x);Splay(x);PushR(x);return;}
	void Link(int x,int y)
	{Access(x);fa[x]=y;return;}
	void Cut(int x,int y)
	{Access(x);Splay(y);fa[x]=t[y][1]=0;PushUp(y);return;}
	int FindRoot(int x){
		Access(x);Splay(x);PushDown(x);
		while(t[x][0])x=t[x][0],PushDown(x);
		Splay(x);return x;
	}
}T;
int MIX(int l,int r){
	if(r>n)return 1e9+7;
	int z=lg[r-l+1];
	int x=max(g[l][z],g[r-(1<<z)+1][z]);
	int y=min(f[l][z],f[r-(1<<z)+1][z]);
	return x-y;
}
int nxts(int x,int w){
	int l=x,r=n;
	while(l<=r){
		int mid=(l+r)>>1;
		if(MIX(x,mid)<=w)l=mid+1;
		else r=mid-1;
	}
	return l;
}
int main()
{
	scanf("%d%d%d",&n,&w,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),f[i][0]=g[i][0]=a[i];
	for(int j=1;(1<<j)<=n;j++)
		for(int i=1;i+(1<<j)-1<=n;i++){
			f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
			g[i][j]=max(g[i][j-1],g[i+(1<<j-1)][j-1]);
		}
	for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n+1;i++)T.siz[i]=1;
	for(int i=1;i<=n;i++){
		t[i]=1,T.Link(i,i+t[i]);
		h.push(mp(-MIX(i,i+1),i));
	}
	for(int i=1;i<=m;i++)
		scanf("%d",&q[i].first),q[i].second=i;
	sort(q+1,q+1+m);reverse(q+1,q+1+m);
	for(int i=1;i<=m;i++){
		int x=w-q[i].first;
		while(!h.empty()&&-h.top().first<=x){
			int p=h.top().second;h.pop();
			T.Cut(p,p+t[p]);t[p]++;
			if(t[p]<=Q){
				T.Link(p,p+t[p]);
				h.push(mp(-MIX(p,p+t[p]),p));
			}
			else t[p]=-1;
		}
		int now=1,sum=0;
		while(now<n+1){
			if(t[now]==-1)now=nxts(now,x),sum++;
			else{
				T.Access(now);T.Splay(now);
				sum+=T.siz[now]-1;
				now=T.FindRoot(now);
			}
		}
		ans[q[i].second]=sum;
	}
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]-1);
	return 0;
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:17:10  更:2022-03-21 21:18:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 1:31:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码