雨巨无敌
方法一:差分
对m个区域进行差分数组delta [ i ]维护
- 本质上是 如果有一个区间砍树 相应的原数组就+1。
- 在差分数组上表现为 区间左端点 +1 区间右端点的下一个 -1
- 维护好这个数组后 求差分数组的前缀和 得到原数组a [ i ]即可 判断是否等于0
- 如果等于0 代表没有被砍树
using namespace std;
/**
采用前缀和与差分的思想
首先维护数组delta[i] 初值都为0
当有某一个区间要砍树时 对应的点就加一 等价为对区间端点进行差分处理
最后求差分数组的前缀和得到原数组
如果原数组值a[i] == 0 那么说明树没砍
计数器cnt++
最后输出cnt
*/
int delta[10010];
int cnt = 0;
int main()
{
int l,m;
scanf("%d%d",&l,&m);
for(int i = 1; i <= m; i++)
{
int x,y;
scanf("%d%d",&x,&y); //区间长度
if(x > y)
swap(x,y);
delta[x]++;
delta[y+1]--;
}
int a = 0;
for(int i = 0; i <= l; i++)
{
a += delta[i];
if(a == 0)
cnt++;
}
cout<<cnt;
}
方法二:划分区域
- 用结构体zone去表示数轴上的区域,并按照左端点x的大小进行依次排序。
- 将有交集的区域合并在一起,如果遇到第一个与前一个没有交集的区域,就变成新的left与right,然后在数轴上减去前一段合并区域的长度
using namespace std;
struct zone
{
int x,y;
}a[110]; //用结构体表示区域
bool comp(zone a, zone b)
{
return a.x < b.x;
}
int main()
{
int l,m;
scanf("%d%d",&l,&m);
for(int i = 1; i <= m; i++)
{
scanf("%d%d",&a[i].x,&a[i].y); //给区域初始化
}
sort(a+1,a+1+m,comp); //由于是结构体 因此要自己定义comp 从小到大排序
int left = a[1].x;
int right = a[1].y;
int cnt = l + 1; //树的总数
for(int i = 2; i <= m; i++)
{
if(a[i].x <= right) //这里可以加等号
{
right = max(right,a[i].y);
}
else
{
cnt -= (right - left + 1);
left = a[i].x;
right = a[i].y;
}
}
cnt -= (right - left + 1);
cout<<cnt;
}
方法三 离散化,即区间合并+差分
实际上 在差分的思想中,求前缀和很多时候是无用功,对于一个区间的中间部分,不断的加0还是本身,所以我们思考,用一个结构体,只记录区间端点的num:-1,1,以及他们的位置pos:x,y。当前缀和a==1并且delta[i].num==1时,说明当前i是挖掉树的区间的开始,用delta[i].pos - delta[i-1].pos就可以得到树的个数,加在cnt中即可。最后一段要单独加
using namespace std;
//离散化的思想 即区间合并与前缀和差分的结合体
struct zone
{
int pos,num;
}delta[500];
bool comp(zone a, zone b)
{
return a.pos < b.pos;
}
int main()
{
int l,m;
scanf("%d%d",&l,&m);
for(int i = 1; i <= m ;i++)
{
int x,y;
scanf("%d%d",&x,&y);
delta[i].pos = x;
delta[i].num = 1;
delta[i+m].pos = y+1;
delta[i+m].num = -1;
}
sort(delta+1,delta+1+2*m,comp);
int a = 0;
int cnt = 0;
for(int i = 1; i <= 2*m; i++)
{
a += delta[i].num;
if(a == 1 && delta[i].num == 1)
cnt += (delta[i].pos - delta[i-1].pos);
}
cnt += (l-delta[2*m].pos+1);
cout<<cnt;
}