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]);
}
}

浙公网安备 33010602011771号