YACS 2022年9月月赛 乙组 T1 区间交集(二) 题解
错误的单调队列做法
刚看到这题我觉得是一个类单调队列做法。
先把输入的区间从左到右排序,然后把和第一个区间有交集的区间放到
到第二个时就把前面不合法的删掉,后面如果有新的合法的,就把他放进去。
这样,每一轮结束时
最后还要除以
结果我一交,全错了,但是样例是全对的。。。
自信的代码:
#include <deque> #include <iostream> #include <algorithm> using namespace std; long long ans,tail = 1; struct Node { int l,r; }a[300010]; bool cmp(Node n1,Node n2) { return n1.l < n2.l || n1.l == n2.l && n1.r < n2.r; } int n; deque<Node> d; int main() { cin >> n; for(int i = 1;i <= n;i ++) cin >> a[i].l >> a[i].r; sort(a + 1,a + n + 1,cmp); for(int i = 1;i <= n;i ++) { while(!d.empty() && d[0].r < a[i].l) d.pop_front(); while(tail != n + 1 && a[tail].l <= a[i].r) { d.push_back(Node{a[tail].l,a[tail].r}); tail ++; } ans += d.size() - 1; } cout << ans / 2 << endl; return 0; }
找了半天一个错误样例都找不到,也分析不出来。
后来我用了
这个做法的问题就在于他不会将后面不合法的删掉,除非把前面的全删完。
随便出一个不合法的数据:
3
1 5
2 2
3 3
在
在
所以,这种做法是错误的。
正解,二分
我们来想一想在排好序的区间集合中,和
显然是,我们来看下和
假设这个区间是
也就是说所有左端点小于等于
画个图,就是这样:
因为我们是把区间按照左端点排序的,所以我们可知:符合条件的区间一定是连续的一段。
那么,我们就可以二分他的右端点了。
那么,左端点是谁呢?
这个也好找,就是
每次二分完右端点后,我们只需要拿他减掉
最后需要注意下数据范围
十年心血一场空,不开
证明结束,该算法时间复杂度
展示一下代码:
#include <iostream> #include <algorithm> using namespace std; #define int long long int n,ans; struct Sec { int l,r; }a[300010]; bool cmp(Sec s1,Sec s2) { return s1.l < s2.l || s1.l == s2.l && s1.r < s2.r; } int check(int x) { int l = 1,r = n,mid; int ret = n + 1; while(l <= r) { mid = l + r >> 1; if(a[mid].l > x) { ret = mid; r = mid - 1; } else l = mid + 1; } return ret; } signed main() { cin >> n; for(int i = 1;i <= n;i ++) scanf("%d%d",&a[i].l,&a[i].r); sort(a + 1,a + n + 1,cmp); for(int i = 1;i <= n;i ++) ans += check(a[i].r) - i - 1; cout << ans << endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异