线段树·P1247贪婪大陆

题目描述

人类被蚂蚁们逼到了 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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值