Abstract

HDU 4343 Interval query

离线查询 倍增祖先

10级的就别看了,11级的读一下。

Body

Source

http://acm.hdu.edu.cn/showproblem.php?pid=4343

Description

给定N(N<=100000)个区间(左闭右开)和M(M<=100000)个询问[l, r],问所有满足[s,t)包含于于[l, r]的区间中最多能选出多少个,使得他们两两不相交。

Solution

首先是一个贪心的想法,如果存在两个区间[s1,t1)和[s2,t2),且[s1,t1)包含于[s2,t2),那么[s2,t2)是可以扔掉的。很显然地,如果[s2,t2)包含于某个解中,那么把它换成[s1,t1)肯定个数不变。

所以就可以把包含了其它区间的那些区间去掉。具体做法是天王想的,特别抽,详见代码。

其实这步做不做无所谓,因为最坏情况下不会扔掉任何一个区间。但事实证明做了这一步就可以O(N*M)暴力水过……

剩下来的区间按左端点升序排序,那么右端点一定也是升序的。

然后求方案其实还是一个贪心的想法,对于一个询问[l, r],设i=max{i|t[i]<=r},如果s[i]>=l,那么就选上i,然后设prev[i]=max{j|j<i且t[j]<=s[i]},也就是prev[i]为i之前最右边的和i不相交的区间,如果s[prev[i]]>=l,那么就选上prev[i]。就这样不停贪心地向前找,直到找到某个j=max{j|s[j]<l},那么j就不能选了。这么做的正确性也很显然,就不证了。

于是我们发现,这些线段就形成了一个树型结构,除了第一个线段,每个线段都有其前继。线段的排序是这颗有向树的拓扑排序的一种。

如果将询问排序按右端点排序后,容易用均摊线性时间找到对于询问[l, r]的终止节点i=max{i|t[i]<=r}。那么接下来就是顺着前继向前找,直到发现j=max{j|s[j]<l}。

暴力找的复杂度是O(N),有M个询问,也就是总共是O(N*M)。由于数据比较水,在第一个贪心思路把没用的区间去掉后可以750ms通过(RunID=6472102,似乎比不加这个优化然后正经做的都要快……)。

稍微思考一下。顺着前继向前找,一直找到最左边,这样找到的节点形成了一条链。很显然,链上的左端点是单调的,这给了我们二分的启示。

但是普通的二分需要存储每一条链,这在时间和空间上都是不允许的。

将ans进行二进制表示,令ans=2^k*b[k]+2^(k-1)*b[k-1]+...+2^0*b[0],b[t]=0或1, t=k,k-1,...,0,可以发现,二分的过程事实上就是根据当前的ans判断出每一个b[t], t=k,k-1,...,0是1还是0的过程。

这样就可以利用类似于最近公共祖先(LCA)的倍增法的思路,记录i的2^j祖先,也就是i节点向前找2^j是什么节点。然后就可以根据每次向前找2^j, j=k,k-1,...,0后,节点的左端点是否还满足s[j]>=l来判断ans的二进制表示中第j位是1还是0了。

Code

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;struct ss {ss() {}ss(int a, int b): s(a), t(b) {}int s, t;int p, q;bool vis;bool operator<(const ss &rhs)const {return t<rhs.t;}void write() {printf("%d %d\n", s, t);}
};bool cmp(const ss &u, const ss &v) {if (u.p==v.p) return u.q>v.q;return u.p<v.p;
}struct sq {int id;int s, t;bool operator<(const sq &rhs) const {return t<rhs.t;}
}q[100010];const int INF = 1000000001;
int N, M;
ss hmr[100010], mdk[100010];
int ans[100010];
int prev[100010][22];int main() {int i, j, k;while (~scanf("%d%d", &N, &M)) {for (i = 0; i < N; ++i) {scanf("%d%d", &hmr[i].s, &hmr[i].t);hmr[i].p = hmr[i].t;hmr[i].q = INF+hmr[i].s;hmr[i].vis = 0;}sort(hmr, hmr+N, cmp);for (i = 0; i < N; ) {j = i+1;while (j<N && hmr[j].q <= hmr[i].q) hmr[j++].vis = 1;i = j;}j = 0;for (i = 0; i < N; ++i)if (!hmr[i].vis) mdk[++j] = hmr[i];N = j;sort(mdk+1, mdk+N+1);mdk[0] = ss(-2, -1);for (i=0,j=1; j<N; ++i,j<<=1);int bmax = i;k = 1;for (i = 1; i <= N; ++i) {while (mdk[k].t<=mdk[i].s) k++;prev[i][0] = k-1;}prev[0][0] = 0;for (j = 1; j <= bmax; ++j) {prev[0][j] = 0;for (i = 1; i <= N; ++i) {prev[i][j] = prev[prev[i][j-1]][j-1];}}for (i = 0; i < M; ++i) {scanf("%d%d", &q[i].s, &q[i].t);q[i].id = i;}sort(q, q+M);k = 0;int b;for (i = 0; i < M; ++i) {while (k<=N && mdk[k].t <= q[i].t) k++;int &res = ans[q[i].id], now = k-1;res = 0;for (j=bmax; j>=0; j--) {if (mdk[prev[now][j]].s>=q[i].s) {res |= (1<<j);now = prev[now][j];}}if (mdk[k-1].s >= q[i].s) res++;}for (i = 0; i < M; ++i)printf("%d\n", ans[i]);}return 0;
}

转载于:https://www.cnblogs.com/jffifa/archive/2012/08/08/2627536.html

[报告]HDU 4343 Interval query相关推荐

  1. hdu 4343 Interval query

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4343 题目大意:求区间最多有多少不相交线段. 题目思路:先用倍增思想求出dp[i][j]表示左端点为j ...

  2. HDU 4343 Interval query 倍增思想, DP

    题目大意: 就是现在给出N个区间(纠结了一下应该都是开区间), 区间(l, r)满足两边端点都是不超过10^9的非负整数, 现在有M次询问, 每次询问区间(L, R)中最多可以找出多少个区间(来自于N ...

  3. HDU 4343 Interval query(倍增思想+贪心)

     题意:给定n(n<=100000)个区间(左闭右开)和m(m<=100000)次询问[l, r],问所有在[l, r]区间内最多有多少个两两不相交的区间., 思路:首先贪心的思想,去 ...

  4. HDU  4343 Interval query

    HDU 4343 Interval query 题目给定nn个区间(li,ri),1≤i≤n(l_i,r_i),1\leq i\leq n MM次询问.询问在区间[L,R][L,R]上,有多少个互不相 ...

  5. 【HDOJ】4343 Interval query

    最大不相交集合的数量. 思路是dp[i][j]表示已经有i个不相交集合下一个不相交集合的最右边界. 离散化后,通过贪心解. 1 /* 4343 */ 2 #include <iostream&g ...

  6. HDU 4343 贪心

    D - Interval query Time Limit: 1.5 Sec Memory Limit: 256 MB Description This is a very simple questi ...

  7. 【HDU 4343】Interval query(倍增)

    BUPT2017 wintertraining(15) #8D 题意 给你x轴上的N个线段,M次查询,每次问你[l,r]区间里最多有多少个不相交的线段.(0<N, M<=100000) 限 ...

  8. HDU4343[Interval query]--倍增思想+二分+离散

    博主吐槽一下:本蒟蒻差点就屎在这道鬼畜题上了QAQ(大佬可以忽视) [链接] HDU4343 [题目大意] 给你N个区间,和M个询问,对于每个询问,输出询问的一段区间内最多有多少段互不相交的区间. [ ...

  9. HDU 4343 贪心+倍增

    Problem DescriptionThis is a very simple question. There are N intervals in number axis, and M queri ...

  10. Interval query

    题意: 给出数轴上的N个区间,M个询问"QUERY(a, b)", 意为[a, b]之间不相交的集合的最大数量是多少. 解法: 考虑 $O(n)$ 的贪心做法,预处理出对于每一个位 ...

最新文章

  1. WiFi漫游了解一下?大户型wifi组网方案
  2. 【体验】TLD5098EL英飞凌恒流电源开发板,恒定电流源LED驱动板
  3. 13、Java Swing事件监听:事件处理模型和事件监听器
  4. JAVAEE联邦软件管理系统试题
  5. pandas python groupby_Python Pandas与Groupby的条件和
  6. 如何禁止谷歌浏览器隐藏url的www前缀
  7. Java后台POST请求以application/x-www-form-urlencoded;charset=utf-8格式
  8. Apollo灰度发布
  9. 华为机试HJ83:二维数组操作
  10. CString.Format详解【摘录】
  11. 手把手教你使用Python做数据分析
  12. vb是计算机语言吗,vb是什么语言?
  13. pyqt5 加载gif_PyQt5:在Qmovi中重新加载gif
  14. 【机器学习入门】(6) 随机森林算法:原理、实例应用(沉船幸存者预测)附python完整代码和数据集
  15. 工作组计算机设置网络密码,设置访问工作组计算机需要密码问题
  16. 考研英语近义词与反义词·三
  17. 【程序员学理财】有哪些普通人应该知道的经济学常识?
  18. facebook第三方登录前后端分离
  19. LaTex 自动生成IEEE格式的参考文献
  20. HYPOTHESES ON THE EXISTENCE OF ADVERSARIAL EXAMPLES

热门文章

  1. 中文分词与马尔科夫模型之二(隐马尔科夫模型与维特比)
  2. 离散数学复习--第一章:命题逻辑
  3. Hamilton-Caylay (哈密尔顿-凯莱)定理
  4. 使用Uchihash处理恶意软件中的嵌入式哈希
  5. 八个小技巧教你做出舒服的MG动画
  6. Raki的读paper小记:SUBSPACE REGULARIZERS FOR FEW-SHOT CLASS INCREMENTAL LEARNING
  7. 神经网络与深度学习第2章:机器学习概述 阅读提问
  8. macbook 安装任意来源
  9. 构建之法阅读笔记三—结对编程
  10. LightOj 1088 - Points in Segments (二分枚举)