贪婪大陆
题目描述
人类被蚂蚁们逼到了 Greed Island 上的一个海湾。现在,小 FF 的后方是一望无际的大海, 前方是变异了的超 级蚂蚁。 小 FF 还有大好前程,他可不想命丧于此, 于是他派遣手下最后一批改造 SCV 布置地雷以阻挡蚂蚁们的进攻。
小 FF 最后一道防线是一条长度为 N 的战壕, 小 FF 拥有无数多种地雷,而 SCV 每次 可以在[ L , R ]区间埋放同一种不同于之前已经埋放的地雷。 由于情况已经十万火急,小 FF 在某些时候可能会询问你在[ L' , R'] 区间内有多少种不同的地雷, 他希望你能尽快的给 予答复。
输入格式
第一行为两个整数 n 和 m; n 表示防线长度, m 表示 SCV 布雷次数及小 FF 询问 的次数总和。
接下来有 m 行, 每行三个整数 Q,L , R; 若 Q=1 则表示 SCV 在[ L , R ]这段区间 布上一种地雷, 若 Q=2 则表示小 FF 询问当前[ L , R ]区间总共有多少种地雷。
输出格式
对于小 FF 的每次询问,输出一个答案(单独一行),表示当前区间地雷总数。
样例数据
input
5 4
1 1 3
2 2 5
1 2 4
2 3 5
output
1
2
这个题目区间修改与查询,很明显是线段树的题。
显然这题不能用简单的区间累加求最大值。 那么这题到底怎么做呢emmmm,
错误的思路1:对地雷的区间累加求和 这个很显然是错的。
错误的思路2:对于每一个与地雷区间[L,R]有部分重叠就累加,因为显然这种时候这个区间的地雷数会加一。这个思路貌似非常的正确。然而执行的时候发现根本无法查询,如果要查询的区间属于两串树,恭喜你GG。
一开始我想到的就是思路2,然后就错了。
问了老师才明白其中的奥妙。这题要用逆向思维。既然处理区间内的地雷数很难处理,那么处理不在区间内的地雷数呢?区分以下左右思路就非常清晰了:在线操作,输入一组地雷的区间,对区间左侧所有区间(点)的 “右边存在地雷数”+1。对区间右侧所有区间(点)的“左边存在地雷数”+1。最后查询的时候只要搜索需要查的区间的左右端点 用总地雷数减去这两个数就能过了。
然而我一开始漏了一种情况,即这个区间是一个重合的点,即L=R,于是 ....青草池塘处处WA。
下面是两套代码:
//代码1
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,ans,ll,rr,sum;
struct shu
{
int leftpoint,rightpoint;
int lazyleft,lazyright;
}tree[401000];
int read()
{
int num=0;
char c=getchar();
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())num=num*10+c-'0';
return num;
}
void add(int left,int right,int temp)
{
if(x<=left&&y>=right) return;
if(right<x) {tree[temp].rightpoint++;tree[temp].lazyright++;return;}
if(left>y) {tree[temp].leftpoint++;tree[temp].lazyleft++;return;}
if(left==right) return;
tree[temp*2].rightpoint+=tree[temp].lazyright;
tree[temp*2].lazyright+=tree[temp].lazyright;
tree[temp*2+1].rightpoint+=tree[temp].lazyright;
tree[temp*2+1].lazyright+=tree[temp].lazyright;
tree[temp*2].leftpoint+=tree[temp].lazyleft;
tree[temp*2].lazyleft+=tree[temp].lazyleft;
tree[temp*2+1].leftpoint+=tree[temp].lazyleft;
tree[temp*2+1].lazyleft+=tree[temp].lazyleft;
tree[temp].lazyleft=0;
tree[temp].lazyright=0;
int mid;
mid=(left+right)/2;
add(left,mid,temp*2);
add(mid+1,right,temp*2+1);
return;
}
void find(int left,int right,int temp)
{
if(x>right||y<left) return;
bool blag=false;
if(x==left&&x==right) {ll=tree[temp].leftpoint;blag=true;}
if(y==right&&y==left) {rr=tree[temp].rightpoint;blag=true;}
if(blag) return;
if(left>x&&right<y) return;
tree[temp*2].rightpoint+=tree[temp].lazyright;
tree[temp*2].lazyright+=tree[temp].lazyright;
tree[temp*2+1].rightpoint+=tree[temp].lazyright;
tree[temp*2+1].lazyright+=tree[temp].lazyright;
tree[temp*2].leftpoint+=tree[temp].lazyleft;
tree[temp*2].lazyleft+=tree[temp].lazyleft;
tree[temp*2+1].leftpoint+=tree[temp].lazyleft;
tree[temp*2+1].lazyleft+=tree[temp].lazyleft;
tree[temp].lazyleft=0;
tree[temp].lazyright=0;
int mid;
mid=(left+right)/2;
find(left,mid,temp*2);
find(mid+1,right,temp*2+1);
return ;
}
int main()
{
n=read();
m=read();
memset(tree,0,sizeof(tree));
int hh;
for(int i=1;i<=m;i++)
{
hh=read(),x=read(),y=read();
if (hh==1)
{
add(1,n,1);sum++;
}
if(hh==2)
{
find(1,n,1);
printf("%d\n",sum-ll-rr);
//printf("sum=%d ll=%d rr=%d\n",sum,ll,rr);
}
}
return 0;
}
//代码2
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,ll,rr,sum=0;
struct shu
{
int leftpoint,rightpoint,lazyleft,lazyright;
}tree[401000];
int read()
{
int num=0;
char c=getchar();
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())num=num*10+c-'0';
return num;
}
void add(int left,int right,int temp,int R)
{
if(x>right||y<left) return;
if(x<=left&&y>=right)
{
if(R==0){tree[temp].rightpoint++;tree[temp].lazyright++;return;}
if(R==1){tree[temp].leftpoint++;tree[temp].lazyleft++;return;}
return;
}
tree[temp*2].rightpoint+=tree[temp].lazyright;
tree[temp*2].lazyright+=tree[temp].lazyright;
tree[temp*2+1].rightpoint+=tree[temp].lazyright;
tree[temp*2+1].lazyright+=tree[temp].lazyright;
tree[temp*2].leftpoint+=tree[temp].lazyleft;
tree[temp*2].lazyleft+=tree[temp].lazyleft;
tree[temp*2+1].leftpoint+=tree[temp].lazyleft;
tree[temp*2+1].lazyleft+=tree[temp].lazyleft;
tree[temp].lazyleft=0;
tree[temp].lazyright=0;
int mid=(left+right)/2;
add(left,mid,temp*2,R);
add(mid+1,right,temp*2+1,R);
return;
}
void find(int left,int right,int temp,int R)
{
if(x>right||y<left) return;
if(x==left&&y==right&&R==0) {ll=tree[temp].leftpoint;return;}
if(x==left&&y==right&&R==1) {rr=tree[temp].rightpoint;return;}
tree[temp*2].rightpoint+=tree[temp].lazyright;
tree[temp*2].lazyright+=tree[temp].lazyright;
tree[temp*2+1].rightpoint+=tree[temp].lazyright;
tree[temp*2+1].lazyright+=tree[temp].lazyright;
tree[temp*2].leftpoint+=tree[temp].lazyleft;
tree[temp*2].lazyleft+=tree[temp].lazyleft;
tree[temp*2+1].leftpoint+=tree[temp].lazyleft;
tree[temp*2+1].lazyleft+=tree[temp].lazyleft;
tree[temp].lazyleft=0;
tree[temp].lazyright=0;
int mid=(left+right)/2;
find(left,mid,temp*2,R);
find(mid+1,right,temp*2+1,R);
return;
}
int main()
{
n=read();
m=read();
memset(tree,0,sizeof(tree));
int hh,xx,yy;
for(int i=1;i<=m;i++)
{
hh=read();xx=read();yy=read();
if(hh==1)
{
sum++;
x=1,y=xx-1;
add(1,n,1,0);
x=yy+1,y=n;
add(1,n,1,1);
}
if(hh==2)
{
x=y=xx;
find(1,n,1,0);
x=y=yy;
find(1,n,1,1);
printf("%d\n",sum-ll-rr);
//printf("%d %d %d\n\n",sum,ll,rr);
}
}
return 0;
}