首页 > 其他分享 >CF1034D Intervals of Intervals 题解

CF1034D Intervals of Intervals 题解

时间:2023-05-02 14:13:40浏览次数:55  
标签:log 题解 ll mid 区间 Intervals CF1034D 价值 线段

传送门

CF1034D Intervals of Intervals

题目大意

有 \(n\) 个线段,第 \(i\) 个是 \([a_i,b_i]\)。

定义区间 \([l,r]\) 的价值是第 \(l\) 个线段到第 \(r\) 个线段的并的长度。

找出 \(k\) 个不同的区间,使得总价值最大。输出最大总价值。

\(1 \le n \le 3 \times 10^5,1 \le k \le \min\{ \frac{n(n+1)}{2},10^9 \},1 \le a_i < b_i \le 10^9\)。

思路

我们肯定会选出价值前 \(k\) 大的区间。因为 \(k\) 很大,所以我们可以尝试二分价值第 \(k\) 大的区间的价值

我们设二分的值为 \(mid\),那么问题就变为了求价值大于等于 \(mid\) 的区间个数。

要求解这个问题,我们肯定需要一种算法,能够处理到所有区间的价值。

因为是求线段并集,我们考虑转化为染色问题,第 \(i\) 个线段的颜色为 \(i\),没有被染色的位置颜色是 \(0\)。

我们按 \(1\) 到 \(n\) 的顺序依次加入线段 \(r\),那么对于任意 \(l\),区间 \([l,r]\) 的价值就是当前颜色编号大于等于 \(l\) 的位置个数。

如果我们记录 \(c_l\) 为区间 \([l,r]\) 的价值,那么其实这就是一个 \(c\) 数组的区间加法。这可以使用树状数组直接维护。

因为染色的过程是区间赋值,可以使用 ODT 维护。

ODT(Old Driver Tree,俗称珂朵莉树),就是把具有相同值 \(x\) 的一段连续区间 \([l,r]\) 压成一个三元组 \((l,r,x)\)。三元组存入 set,维护区间修改时暴力合并分裂区间即可。

这样我们就用 \(O(n \log n)\) 的时间完成了所有区间价值的处理。

但是注意我们的问题是求价值大于等于 \(mid\) 的区间个数。

容易发现,区间的价值(设为 \(w_{l,r}\))具有一定的单调性:\(w_{l,r} \ge w_{l+1,r},w_{l,r} \ge w_{l,r+1}\)。

也就是说,对于每个 \(r\),如果区间 \([l,r]\) 满足条件,那么 \(\forall i < l\),区间 \([i,r]\) 满足条件;且 \(r\) 单调递增时,\(l\) 单调不减。

所以我们可以使用双指针,找出最后一个价值大于等于 \(mid\) 的区间,这样我们就可以用 \(O(n \log n)\) 的时间统计区间个数。

所以我们的总体复杂度就可以做到 \(O(n \log n \log k)\)。

显然这样的复杂度是不能通过的。我们需要优化。

可以发现,其实我们可以只跑一次 ODT,记录修改操作。然后在二分 \(mid\) 时,用差分数组重做这些操作就好了,这样就少了一个 \(\log\)。

然后就做完了。复杂度 \(O(n \log n + n \log k)\)。

代码实现

可以把二分的 check 和求答案放在一起写。

注意变量名不要写错了。

check 的写法需要注意。

#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
#define pb push_back
const ll N=1e6+10;
using namespace std;

ll n,k;
ll a[N],b[N];//线段

struct node{
	ll l,r,c;
	bool operator<(const node&a)const{
		return l<a.l||l==a.l&&r<a.r;
	}
};
set<node>s;//ODT
vector<node>op[N];//记录原始的区间,用于覆盖的区间就是(a[i],b[i],i),无需记录
void init(){
	s.insert({0,(ll)1e9,0});//一开始都是0
	For(i,1,n){
		auto it=s.lower_bound({a[i],(ll)1e9,0});//找到一条过点a[i]的色块
		--it;
		ll l=it->l,r=it->r,c=it->c;
		//整条线段被色块包含
		if(r>=b[i]){
			s.erase(it);
			op[i].pb({a[i],b[i],c});
			if(l<a[i])s.insert({l,a[i]-1,c});
			if(r>b[i])s.insert({b[i]+1,r,c});
			s.insert({a[i],b[i],i});
			continue;
		}
		//线段最左端的色块
		s.erase(it++);
		op[i].pb({a[i],r,c});
		if(l<a[i])s.insert({l,a[i]-1,c});
		//线段包含的色块
		while(it->r<b[i]){
			op[i].pb(*it);
			s.erase(it++);
		}
		//线段最右端的色块
		l=it->l,r=it->r,c=it->c;
		s.erase(it);
		op[i].pb({l,b[i],c});
		if(r>b[i])s.insert({b[i]+1,r,c});
		s.insert({a[i],b[i],i});
	}
}

ll ans;
ll d[N];//差分数组
ll check(ll mid){
	ans=0;//价值大于等于mid的区间价值和
	ll s=0;//差分数组L位置到R位置的总和
	ll now=0;//差分数组1位置到L-1位置代表的区间价值和
	ll res=0;//价值大于等于mid的区间数量
	ll L=1;//左端点
	For(R,1,n){//右端点
		d[R]=b[R]-a[R]+1;//预处理为长度
		s+=d[R];
		for(auto j:op[R]){
			ll l=j.l,r=j.r,c=j.c;
			d[c]-=r-l+1;//差分
			if(c>=L)s-=r-l+1;
			if(c&&c<L)now-=c*(r-l+1);
		}
		while(s>=mid){
			s-=d[L];
			now+=L*d[L];
			L++;//左端点移动
		}
		ans+=now+s*(L-1);//统计答案
		res+=L-1;//统计个数
	}
	ans-=mid*(res-k);//我们只需要求前k大的总和,多出来的区间减掉
	return res>=k;
}

void mian(){
	
    scanf("%lld%lld",&n,&k);
	For(i,1,n){
		scanf("%lld%lld",&a[i],&b[i]);
		b[i]--;//转成闭区间
	}
	init();
	ll l=0,r=1e9,len=0;
	while(l<=r){
		ll mid=l+r>>1;
		if(check(mid)){
			len=mid;
			l=mid+1;
		}else r=mid-1;
	}
	check(len);
	printf("%lld",ans);
	
}

int main(){
	int T=1;
//	scanf("%d",&T);
	while(T--)mian();
	return 0;
}

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

标签:log,题解,ll,mid,区间,Intervals,CF1034D,价值,线段
From: https://www.cnblogs.com/zsc985246/p/17367616.html

相关文章

  • asm_second 题解(坐标转换+二维偏序)
    QuestionAsm.Def在第一象限内找到了n个可疑点。他需要为导弹规划路径。如图所示,导弹一开始在(0,0)。它只能朝着一定的方向——即严格夹在图中两条射线间的方向(白色部分)前进。注意,它不能沿着这两条射线前进,当然也不能停在原地。当导弹到达某个可疑点后,它仍然只能朝着该范围内......
  • 2023湖北CCPC省赛 蒻蒟的部分题解
    题目地址C.DarknessI题意:有一个n*n的方格,最开始全是白色,如果白色周围4格有两个黑色格子,1秒后这个白色格子会变成黑色,问如果要使全部格子都变为黑色,最开始最少需要涂黑几个格子Solution对于两个黑色格子,只有当满足\[|x_1-x_2|+|y_1-y_2|≤2\]才能涂黑以这两个格子为顶点的矩......
  • 2023 Hubei Provincial Collegiate Programming Contest题解 C F H I J K M
    补题链接:https://codeforces.com/gym/104337原文链接:https://www.eriktse.com/algorithm/1136.htmlM.DifferentBilling签到题,写几个柿子然后枚举B或C即可。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;signedmain(){ ios::sync_with_stdio(......
  • CF1477F Nezzar and Chocolate Bars 题解
    题意:有一根长为\(1\)的巧克力,已经被切了\(m-1\)刀被分成\(m\)分,接下来每次在整根长度为\(1\)的巧克力上均匀随机一个点切一刀,求每一小段巧克力长度均小于一个给定值\(K\)需要的期望次数。引理:Irwin-Hall分布:对于\(n\)个在\([0,1]\)内均匀分布的实数随机变量,它们......
  • 4 月 30 日测试题解
    4月30日测试题解T1\({\color{green}{\text{100pts}}}\text{/100pts}\)题意一个无限长宽的棋盘,给出起点\(s\)和终点\(t\),行走方式是象棋中马的走法,问最少需要走多少步。对于\(100\%\)的数据,\(|x_s|,|y_s|,|x_t|,|y_t|\le10^7\)。思路\(\text{100pts}\)首先,坐......
  • 【题解】P3338 [ZJOI2014]力
    题目描述给出\(n\)个数\(q_1,q_2,\dotsq_n\),定义\[F_j~=~\sum_{i=1}^{j-1}\frac{q_i\timesq_j}{(i-j)^2}~-~\sum_{i=j+1}^{n}\frac{q_i\timesq_j}{(i-j)^2}\]\[E_i~=~\frac{F_i}{q_i}\]对\(1\leqi\leqn\),求\(E_i\)的值。\(1\le......
  • [P5785 [SDOI2012]任务安排] 题解
    P5785[SDOI2012]任务安排题目描述分析很明显是一个dp我们不妨设\(dp[i]\)表示枚举到\(i\)的最小费用\(t[i]\)表示加工完第\(i\)个任务所用的总时间,也就是\(T[i]\)的前缀和由于每一批任务前都要一个时间为\(s\)的开机工作我们不妨把每一个这样的\(s\)秒提出来,则这\(s\)秒都......
  • CF1624G 题解
    前言题目传送门!更好的阅读体验?比较好玩的二进制题目。思路答案最小,也就是说较高位要尽可能小。所以很容易想到从最高位开始枚举。第\(i\)位为\(0\),等价于选出的所有边的第\(i\)位都为\(0\)。同时,由于我们是贪心,如果之前枚举过的第\(j\)位可以是\(0\),那么这两个条件......
  • 洛谷 P7579 「RdOI R2」称重(weigh) 题解
    题意:题目一道交互题。有n个球,里面有两个假球,假球比普通球的要轻,每次可以询问任意两组球的轻重关系,第一组轻为<,第二组轻为>,一样重量为=。思路:先考虑在一个区间内找1个假球。我们可以将区间尽量平均分为3份,先询问相等的两组球的轻重关系,分3种情况:第一组轻......
  • 【题解】CF44G Shooting Gallery
    题目大意给定\(n\)个三维空间的平面,由高度\(z\)、\(x\)的范围\([xl,xr]\)和\(y\)的范围\([yl,yr]\)来表示。有\(m\)次射击,每次射击点\((x,y)\),摧毁包含此点的\(z\)值最小的平面,输出此平面编号,若摧毁不了任何平面,输出\(0\)。题解点查平面不好做,于是可以转化为平面查点,先将平面按......