luogu题解 P2184 【贪婪大陆】
-
题目链接:
-
思路:
首先我想吐槽一下为什么现有题解中的做法都是一样的,而且还比较难以理解;
我就讲下我的做法,本质上是一样的,但是跟容易理解.
根据题意每加一次地雷就多一个种类对吧,我们用一个cnt记录加过地雷的次数,同时分别用两个数组记录左右两个端点的位置。然后查询[l,r]时呢,我们分别查询[1,l-1]有多少个右端点,[r+1,n]有多少个左端点,然后这两个数的和是什么意思呢?就是有多少次铺地雷没铺到我们查询的这个[l,r]区间。
最后cnt-刚刚两次查询的和就是有多少次地雷铺到了[l,r]这个区间,输出即可,当然,我们用线段树维护这些操作。
-
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;
const int maxn=100005;
int sum_r[maxn<<2],sum_l[maxn<<2],add[maxn<<2];
int n,m;
int L,R;
void update_l(int now,int l,int r,int t){
if(l==r){
sum_l[now]++;
return ;
}
int mid=(l+r)>>1;
if(t<=mid)update_l(now<<1,l,mid,t);
else update_l(now<<1|1,mid+1,r,t);
sum_l[now]=sum_l[now<<1]+sum_l[now<<1|1];
return ;
}
void update_r(int now,int l,int r,int t){
if(l==r){
sum_r[now]++;
return ;
}
int mid=(l+r)>>1;
if(t<=mid)update_r(now<<1,l,mid,t);
else update_r(now<<1|1,mid+1,r,t);
sum_r[now]=sum_r[now<<1]+sum_r[now<<1|1];
return ;
}
int query_l(int now,int l,int r){
if(L<=l&&r<=R){
return sum_l[now];
}
int mid=(l+r)>>1;
int ans=0;
if(L<=mid)ans+=query_l(now<<1,l,mid);
if(mid<R)ans+=query_l(now<<1|1,mid+1,r);
return ans;
}
int query_r(int now,int l,int r){
if(L<=l&&r<=R){
return sum_r[now];
}
int mid=(l+r)>>1;
int ans=0;
if(L<=mid)ans+=query_r(now<<1,l,mid);
if(mid<R)ans+=query_r(now<<1|1,mid+1,r);
return ans;
}
int main()
{
int op,l,r;
int cnt=0,tmp=0;
scanf("%d %d",&n,&m);
for(register int i=1;i<=m;i++){
scanf("%d %d %d",&op,&l,&r);
if(op==1){
update_l(1,1,n,l);
update_r(1,1,n,r);
cnt++;
}
else {
L=r+1,R=n;
if(L<=R)tmp+=query_l(1,1,n);
L=1,R=l-1;
if(L<=R)tmp+=query_r(1,1,n);
cout<<cnt-tmp<<endl;
tmp=0;
}
}
return 0;
}