CodeVS1299

题目描述 Description

简单的说,一共N个水果排成一排,切M次,每次切[L,R]区间的所有水果(可能有的水果被重复切),每切完一次输出剩下水果数量

数据已重新装配,不会出现OLE错误

时限和数据范围适当修改,避免数据包过大而浪费空间资源

输入描述 Input Description

第1行共包括2个正整数,分别为N,M。

接下来m行每行两个正整数L,R 

输出描述 Output Description

一共输出M行,每行输出切完之后剩下水果数量

样例输入 Sample Input

10 3

3 5

2 8

1 5

样例输出 Sample Output

7

3

2

数据范围及提示 Data Size & Hint

30%的数据满足N,M<=5,000

60%的数据满足N,M<=100,000

100% 的数据满足1<=L<=R<=N<=500,000,1<=M<=500,000

线段树裸题,直接维护区间个数就行。

还有一种神奇的思路,用并查集维护下一个非空位置。

 

并查集版本:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

using namespace std;

const int N = 500010;

int n, m, fa[N], sum;

int main() {
	scanf("%d%d", &n, &m);
	sum = n;
	for(int i = 1, l, r ; i <= m ; i ++) {
		scanf("%d%d", &l, &r);
		if(l > r) swap(l, r);
		for(int i = l ; i <= min(r, n) ; i ++) {
			if(fa[i]) i = fa[i];
			else fa[i] = r, sum --;
		}
		printf("%d\n", sum);
	}
}

  

 

线段树版本:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

using namespace std;

const int N = 500010 << 2;

int n, m;

int sum[N];

void build(int id, int l, int r) {
	int m = (l + r) >> 1;
	if(l == r) {
		sum[id] = 1;
		return;
	}
	build(id << 1, l, m);
	build(id << 1 | 1, m + 1, r);
	sum[id] = sum[id << 1] + sum[id << 1 | 1];
}

void modify(int id, int l, int r, int L = 1, int R = n) {
	if(L > r || R < l || sum[id] == 0) return;
	int M = (L + R) >> 1;
	if(l <= L && R <= r) {
		sum[id] = 0;
		return;
	}
	modify(id << 1, l, r, L, M);
	modify(id << 1 | 1, l, r, M + 1, R);
	sum[id] = sum[id << 1] + sum[id << 1 | 1];
}

int main() {
	scanf("%d%d", &n, &m);
	build(1, 1, n);
	for(int i = 1, l, r ; i <= m ; i ++) {
		scanf("%d%d", &l, &r);
		modify(1, l, r);
		printf("%d\n", sum[1]);
	}
}
posted @ 2017-08-31 08:43  KingSann  阅读(146)  评论(0)    收藏  举报