您的位置:首页 > 其它

线段树·P1247贪婪大陆

2017-09-26 19:41 281 查看


 贪婪大陆


题目描述

人类被蚂蚁们逼到了 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: