[Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086

额...

首先,看到这道题,第一想法就是二分答案+线段树...

兴高采烈的认为我一定能AC,之后发现n是500000...

nlog^2=80%,亲测可过...

由于答案是求满足题意的最大长度-最小长度最小,那么我们可以考虑将区间按长度排序

之后,因为我们是需要最大最小,所以,我们必定选择在排完序的区间上取连续的一段是最优情况(起码不会比别的差)

因此,考虑双指针扫一下就可以了...

是不是很水?

由于懒得写离散化,一开始写的动态开点线段树,我*****什么鬼?mle?!256mb开不下!

loj+洛谷上95%,附上代码...

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
#define N 500005
#define lson l,m,tr[rt].ls
#define rson m+1,r,tr[rt].rs
#define PushUp(rt) tr[rt].maxx=max(tr[tr[rt].ls].maxx,tr[tr[rt].rs].maxx)
struct no
{
	int ls,rs,maxx,add;
}tr[N*40];
int n,m,ans,cnt;
struct node
{
	int l,r,len;
}a[N];
bool cmp(const node &a,const node &b)
{
	return a.len<b.len;
}
void PushDown(int rt)
{
	if(tr[rt].add)
	{
		if(!tr[rt].ls)tr[rt].ls=++cnt;
		if(!tr[rt].rs)tr[rt].rs=++cnt;
		tr[tr[rt].ls].maxx+=tr[rt].add;
		tr[tr[rt].rs].maxx+=tr[rt].add;
		tr[tr[rt].ls].add+=tr[rt].add;
		tr[tr[rt].rs].add+=tr[rt].add;
		tr[rt].add=0;
	}
}
void Update(int L,int R,bool c,int l,int r,int &rt)
{
	if(!rt)rt=++cnt;
	if(L<=l&&r<=R)
	{
		tr[rt].maxx+=c?1:-1;
		tr[rt].add+=c?1:-1;
		return ;
	}
	PushDown(rt);
	int m=(l+r)>>1;
	if(m>=L)Update(L,R,c,lson);
	if(m<R)Update(L,R,c,rson);
	PushUp(rt);
}
int main()
{
	ans=1<<30;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].l,&a[i].r);
		a[i].len=a[i].r-a[i].l;
	}
	sort(a+1,a+n+1,cmp);
	int l=1,r=0,rot=0;
	while(r<n)
	{
		while(tr[rot].maxx<m&&r<n){r++;Update(a[r].l,a[r].r,1,0,1<<30,rot);}
		if(tr[rot].maxx<m)break;
		while(tr[rot].maxx>=m&&l<n){Update(a[l].l,a[l].r,0,0,1<<30,rot);l++;}
		ans=min(a[r].len-a[l-1].len,ans);
	}
	printf("%d\n",ans==1<<30?-1:ans);
	return 0;
}

  这显然就不能AC,那么我们可以考虑用一下离散化...

离散化后,线段树的空间复杂度从(nlog(1<<30))变成(nlog(n*2))之后,空间就降下来了...

附上AC代码...

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
#define N 500005
#define lson l,m,tr[rt].ls
#define rson m+1,r,tr[rt].rs
#define PushUp(rt) tr[rt].maxx=max(tr[tr[rt].ls].maxx,tr[tr[rt].rs].maxx)
struct no
{
	int ls,rs,maxx,add;
}tr[N*10];
int p[N<<1];
int n,m,ans,cnt;
struct node
{
	int l,r,len;
}a[N];
bool cmp(const node &a,const node &b)
{
	return a.len<b.len;
}
void PushDown(int rt)
{
	if(tr[rt].add)
	{
		if(!tr[rt].ls)tr[rt].ls=++cnt;
		if(!tr[rt].rs)tr[rt].rs=++cnt;
		tr[tr[rt].ls].maxx+=tr[rt].add;
		tr[tr[rt].rs].maxx+=tr[rt].add;
		tr[tr[rt].ls].add+=tr[rt].add;
		tr[tr[rt].rs].add+=tr[rt].add;
		tr[rt].add=0;
	}
}
void Update(int L,int R,bool c,int l,int r,int &rt)
{
	if(!rt)rt=++cnt;
	if(L<=l&&r<=R)
	{
		tr[rt].maxx+=c?1:-1;
		tr[rt].add+=c?1:-1;
		return ;
	}
	PushDown(rt);
	int m=(l+r)>>1;
	if(m>=L)Update(L,R,c,lson);
	if(m<R)Update(L,R,c,rson);
	PushUp(rt);
}
int main()
{
	ans=1<<30;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].l,&a[i].r);
		a[i].len=a[i].r-a[i].l;
		p[(i<<1)-1]=a[i].l;
		p[i<<1]=a[i].r;
	}
	sort(p+1,p+n*2+1);
	for(int i=1;i<=n;i++)
	{
		int x=lower_bound(p+1,p+n*2+1,a[i].l)-p;
		a[i].l=x;
		x=lower_bound(p+1,p+n*2+1,a[i].r)-p;
		a[i].r=x;
	}
	sort(a+1,a+n+1,cmp);
	int l=1,r=0,rot=0;
	while(r<n)
	{
		while(tr[rot].maxx<m&&r<n){r++;Update(a[r].l,a[r].r,1,1,n*2,rot);}
		if(tr[rot].maxx<m)break;
		while(tr[rot].maxx>=m&&l<n){Update(a[l].l,a[l].r,0,1,n*2,rot);l++;}
		ans=min(a[r].len-a[l-1].len,ans);
	}
	printf("%d\n",ans==1<<30?-1:ans);
	return 0;
}

  离散化什么的,用lower_bound就好了,懒得写二分查找了...反正不会tle...

原文地址:https://www.cnblogs.com/Winniechen/p/8989294.html

时间: 2024-10-09 11:52:42

[Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086的相关文章

BZOJ5291/洛谷P4458/LOJ#2512 [Bjoi2018]链上二次求和 线段树

原文链接http://www.cnblogs.com/zhouzhendong/p/9031130.html 题目传送门 - LOJ#2512 题目传送门 - 洛谷P4458 题目传送门 - BZOJ5291 推荐LOJ和洛谷,题面质量好,而且不卡常数. BZOJ题面烂,而且要卡那么一点点常数. 题意 有一条长度为$n$的链$\forall 1≤i<n$,点$i$与点$i+1$之间有一条边的无向图),每个点有一个整数权值,第$i$个点的权值是$a_i$??.现在有$m$个操作,每个操作如下: 操

洛谷P1712 区间

题目描述 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri. 对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度.区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值. 求所有合法方案中最小的花费.如果不存在合法的方案,输出 −1. 输入输出格式

洛谷.3803.[模板]多项式乘法(FFT)

题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. #include <cmath> #include <cctype> #include <cstdio> #include <algorithm> #define gc() getchar() const int N=1e6+5; const double PI=acos(-1); int n,m; struct Complex { double

【BZOJ4653】[Noi2016]区间 双指针法+线段树

[BZOJ4653][Noi2016]区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri. 对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度.区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值. 求所有合法方案中最小

洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)

To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows conveniently numbered 1..N move from the barn to her private pasture. The pastures are organized as a tree, with the barn being on pasture 1. Exactly N-1 cow

洛谷P2879 [USACO07JAN]区间统计Tallest Cow

To 洛谷.2879 区间统计 题目描述 FJ's N (1 ≤ N ≤ 10,000) cows conveniently indexed 1..N are standing in a line. Each cow has a positive integer height (which is a bit of secret). You are told only the height H (1 ≤ H ≤ 1,000,000) of the tallest cow along with th

洛谷P1886 滑动窗口(POJ.2823 Sliding Window)(区间最值)

To 洛谷.1886 滑动窗口 To POJ.2823 Sliding Window 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array is [1 3 -1 -3 5 3 6 7], and k = 3. 输入输出格式 输入格式: 输入一共有两行,第一行为n,k. 第二行为n个数(<INT_MAX). 输出格式: 输出共两行,第一行为每次窗口滑动的最小值

洛谷P1063 能量项链(区间DP)(环形DP)

To 洛谷.1063 能量项链 题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记.因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量.如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为m*r*n(M

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3