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



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

思路:首先贪心的思想,去除掉包含其他区间的大区间,这样做肯定不会影响结果。

然后对于所有区间,按照左端点升序排序,那么由于这时所有区间不相互包含,他们的右端点也是递增的。

那么对于每个询问,肯定是从左到右去尽可能多的区间,这个贪心容易想到。

对数据离散化,记录从每个点开始的经过i个区间所达到的最近距离,这一步用到了倍增的思想,因为如果一个点一个点顺序找,那么时间复杂度和空间复杂度都无法承受。

具体来说,用f[i][j]记录从i出发经过2^j个区间所达到的最近点,那么可以得出递推关系

f[i][j] = f[ f[i][j-1] ][j-1];

那么对于每个询问,我们将询问ql,qr也离散化,只需找到从ql最多经过多少区间使得其不超过qr即可。

ps:半夜睡不着真是心痛,起来补题.........

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#define eps 1e-6
#define LL long long
#define pii (pair<int, int>)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;  

const int maxn = 100000 + 100;
const int INF = 0x3f3f3f3f;
int n, m;
struct Node {
	int l, r;
	bool operator < (const Node& A) const {
		if(l == A.l) return r > A.r;
		return l < A.l;
	}
} node[maxn];
int discret[2*maxn];
int fa[2*maxn][20];

int solve(int l, int r) {
	int ans = 0;
	for(int i = 16; i >= 0; i--) {
		int t = fa[l][i];
	//	cout << t << endl;
		if(t == r) return ans+(1<<i);
		else if(t < r) l = t, ans += (1<<i);
 	}
 	return ans;
}

int main() {
//	freopen("input.txt", "r", stdin);
	while(scanf("%d%d", &n, &m) == 2) {
		memset(fa, INF, sizeof(fa));
		for(int i = 0; i < n; i++) {
			scanf("%d%d", &discret[2*i], &discret[2*i+1]);
			node[i].l = discret[2*i], node[i].r = discret[2*i+1];
		}
		sort(discret, discret+2*n);
		int cnt = unique(discret, discret+2*n)-discret;
		//cout << cnt << endl;
		for(int i = 0; i < n; i++) {
			node[i].l = lower_bound(discret, discret+cnt, node[i].l) - discret;
			node[i].r = lower_bound(discret, discret+cnt, node[i].r) - discret;
		//	cout << node[i].r << endl;
		}
		sort(node, node+n);
		int cnt2 = n-1;
		for(int i = cnt-1; i >= 0; i--) {
		//	cout << node[i].l << endl;
			if(i == node[cnt2].l) {
				fa[i][0] = min(node[cnt2].r, fa[i+1][0]);
				while(i == node[cnt2].l) cnt2--;
			}
			else fa[i][0] = fa[node[cnt2+1].l][0];
		}
		for(int i = 1; i < 17; i++) {
			for(int j = 0; j < cnt; j++) if(fa[j][i-1] != INF) fa[j][i] = fa[ fa[j][i-1] ][i-1];
		}
		for(int i = 0; i < m; i++) {
			int l, r; scanf("%d%d", &l, &r);
			l = lower_bound(discret, discret+cnt, l) - discret;
			r = upper_bound(discret, discret+cnt, r) - discret - 1;
	//		cout << l << " " << r << endl;
			printf("%d\n", solve(l, r));
		}
	//cout << fa[0][0] << endl;
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-08 09:50:55

HDU 4343 Interval query(倍增思想+贪心)的相关文章

HDU 4343 Interval query 倍增思想, DP

注意当两个区间只有一个端点重合时,也算是合法的 题目大意:给定N(N<=100000)个区间(左闭右开)和M(M<=100000)个询问[l, r],问所有满足[s,t)包含于于[l, r]的区间中最多能选出多少个,使得他们两两不相交.解题思路:首先将坐标离散化,将区间排序后删掉可以覆盖其他区间的大区间.这时若将剩余区间的左端点坐标排序,左端点坐标必然严格上升且对应的右端点坐标也是严格上升的.此题的贪心思想较为普及,即按y的升序进行贪心固定区间询问的最大数量,不再赘述.设g[1][x]为从坐标

【HDOJ】4343 Interval query

最大不相交集合的数量.思路是dp[i][j]表示已经有i个不相交集合下一个不相交集合的最右边界.离散化后,通过贪心解. 1 /* 4343 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #in

HDU 4343 贪心

D - Interval queryTime Limit: 1.5 Sec Memory Limit: 256 MB Description This is a very simple question. There are N intervals in number axis, and M queries just like “QUERY(a,b)” indicate asking the maximum number of the disjoint intervals between (a,

HDU 4939 Stupid Tower Defense(贪心+dp)

HDU Stupid Tower Defense 题目链接 题意:有一些塔,红塔能攻击经过他的,绿塔能攻击经过之后的,蓝塔能把经过之后的减速,求在1-n上放塔,求伤害最大值 思路:一开始以为直接贪心,绿塔最前,蓝塔中间,红塔最后就可以了,结果其实是错的 不过,红塔放最后是肯定的,这个很显然就不多证明了,是贪心的思想 然后就dp[i][j]表示放到i,前面有j个绿塔去状态转移即可 代码: #include <cstdio> #include <cstring> #include &l

[BestCoder Round #4] hdu 4932 Miaomiao&#39;s Geometry (贪心)

Miaomiao's Geometry Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 363    Accepted Submission(s): 92 Problem Description There are N point on X-axis . Miaomiao would like to cover them ALL by

HDU 4974 A simple water problem(贪心)

HDU 4974 A simple water problem 题目链接 签到题,很容易贪心得到答案是(sum + 1) / 2和ai最大值的最大值 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 100005; typedef long long ll; int t, n; ll a, Max, sum; int main(

五大算法思想—贪心算法

贪心法理解 贪心法在解决问题的策略上目光短浅,只根据当前已有的信息就做出选择,而且一旦做出了选择,不管将来有什么结果,这个选择都不会改变.换言之,贪心法并不是从整体最优考虑,它所做出的选择只是在某种意义上的局部最优. 一句话:不求最优,只求可行解. 判断贪心法 对于一个具体的问题,怎么知道是否可用贪心算法解此问题,以及能否得到问题的最优解? 我们可以根据贪心法的2个重要的性质去证明:贪心选择性质和最优子结构性质. 1.贪心选择性质 什么叫贪心选择?从字义上就是贪心也就是目光短线,贪图眼前利益,在

ACM学习历程—HDU 4726 Kia&#39;s Calculation( 贪心&amp;&amp;计数排序)

DescriptionDoctor Ghee is teaching Kia how to calculate the sum of two integers. But Kia is so careless and alway forget to carry a number when the sum of two digits exceeds 9. For example, when she calculates 4567+5789, she will get 9246, and for 12

HDU 4883 TIANKENG’s restaurant (贪心)

链接:带我学习,带我飞 第一次BC,稳挂,WA n多次,今天重新做了一下 略挫 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <map> #include <string> #include <vector> #include <set> #include <algorithm>