ABC462D 题解

ABC462D 题解

link.

题目描述

给定 n n n 个区间 l , r l,r l,r,求有多少个 s , i , j s,i,j s,i,j 满足 s , s + d s,s+d s,s+d l i , r i l j , r j l_i,r_i\cap l_j,r_j li,rilj,rj 包含,其中 1 ≤ i < j ≤ n 1\le i<j\le n 1≤i<j≤n。

数据范围请自己看题目。

思路

首先对所有区间进行排序是显然的。以 l l l 为第一关键字,以 r r r 为第二关键字从小到大排。

然后我们发现枚举两个区间的时间复杂度是 O ( n 2 ) O(n^2) O(n2) 的,直接爆炸。

观察一下发现所有区间左右端点的取值范围才 10 6 10^6 106,所以考虑枚举开始作案的时间 s s s。

所以我们可以找到最后一个 满足 l k < s l_k<s lk<s 的区间 k k k,那么包含 s , s + d s,s+d s,s+d 的区间一定是从 1 ∼ k 1\sim k 1∼k 里面找。

给张图理解下。

由于我们的区间是按照 l l l 从小到大排序了,所以在 k k k 之前的区间的 l l l 一定也小于 s s s,也就是一定合法。

现在看怎么找 k k k。

然后注意到我们已经对所有区间排完序了,包含区间 s , s + d s,s+d s,s+d 的区间们在编号上一定也是个区间,且是整体的前缀。

而我们也是从小到大找 s s s 的,所以我们可以不断判断下一个区间的 l l l 是否小于 s s s,时间复杂度均摊 O ( 1 ) O(1) O(1),不懂看代码。

接下来在 1 ∼ k 1\sim k 1∼k 中的区间的左端点一定是合法的,所以只要看多少个右端点大等于 s + d s+d s+d 即可。这个可以用树状数组 O ( log ⁡ n ) O(\log n) O(logn) 求。

假设有 S S S 个区间的右端点大等于 s + d s+d s+d,那么对答案的贡献就是 ( S 2 ) = S ( S − 1 ) 2 \binom{S}{2}=\frac{S(S-1)}{2} (2S)=2S(S−1)。

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ljl;
const int N=2e5+5,M=1e6+5;
int n,cur;
ljl ans,mxr,trc[M],d;
int lowbit(int x){return x&(-x);}
ljl query(int x){
	ljl ans=0;
	for(;x>0;x-=lowbit(x))ans+=trc[x];
	return ans;
}
ljl querylr(ljl l,ljl r){return query(r)-query(l-1);}
void add(int x,ljl val)
{
	for(;x<=mxr;x+=lowbit(x))trc[x]+=val;
	return;
}
struct NODE{
	ljl l,r;
	bool operator < (const NODE a)const{
		if(l!=a.l)return l<a.l;
		return r<a.r;
	}
}node[N];
int main(){
	ios::sync_with_stdio(0);
	cin>>n>>d;
	for(int i=1;i<=n;++i)
	{
		cin>>node[i].l>>node[i].r;
		mxr=max(mxr,node[i].r);
	}
	sort(node+1,node+n+1);
	
	for(ljl st=1;st+d<=mxr;++st)
	{
		while(cur<n&&node[cur+1].l<=st)//这里的cur最多只会增加n次,所以复杂度均摊O(1)
		{
			++cur;
			add(node[cur].r,1ll);
//			cout<<"------\n"; 
		}
		ljl sum=querylr(st+d,mxr);
//		cout<<st<<": "<<sum<<'\n';
		ans=ans+(sum*(sum-1)/2);
	}
	cout<<ans<<'\n';
	return 0;
}
相关推荐
倒头就睡的小比特18 小时前
算法竞赛C++常用的STL
c++·算法
weilx123418 小时前
C++笔记-文件IO-<fcntl.h>
c++
Smileyqp沛沛20 小时前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车20 小时前
C/C++ 为什么需要编译器?
开发语言·c++
ProcessOn官方账号20 小时前
java函数式编程--入门基础
java·编程·函数式编程
旖旎夜光20 小时前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
吞下星星的少年·-·21 小时前
C++ 萌新语法入门篇
c++·算法比赛
霍霍的袁21 小时前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
another heaven21 小时前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
程序猿编码21 小时前
告别改源码适配模型:纯 C++ 可配置 LLM 推理引擎,全格式全结构兼容
c++·大模型·llm·推理引擎