CodeVS1299
题目描述 Description简单的说,一共N个水果排成一排,切M次,每次切[L,R]区间的所有水果(可能有的水果被重复切),每切完一次输出剩下水果数量
数据已重新装配,不会出现OLE错误
时限和数据范围适当修改,避免数据包过大而浪费空间资源
输入描述 Input Description第1行共包括2个正整数,分别为N,M。
接下来m行每行两个正整数L,R
输出描述 Output Description一共输出M行,每行输出切完之后剩下水果数量
样例输入 Sample Input10 3
3 5
2 8
1 5
样例输出 Sample Output7
3
2
数据范围及提示 Data Size & Hint30%的数据满足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]); } }