码迷,mamicode.com
首页 > 其他好文 > 详细

[洛谷P2184]贪婪大陆

时间:2017-12-21 21:48:44      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:int()   时间复杂度   query   一个   sdi   clu   for   ++   void   

题目大意:有n个点,每次在l~r之间所有点各加上同一种地雷,或询问某一区间内地雷种数。

解题思路:首先注意是“加上”而不是“覆盖”。

然后我们用两棵线段树(树状数组),一棵维护某一区间内左端点个数,另一棵维护右端点个数。

由于每次只加上一个端点,故为单点修改。

那么如何查询呢?

如果1~r内有a个左端点,则说明最多有a种地雷,如果1~l-1内有b个右端点,则说明a种地雷中,有b种的右端点没有达到l(否则一定在l-1之后)。

那么查询出a和b,然后输出a-b即可。

很明显是区间修改。

时间复杂度$O(m\log_2 n)$。

C++ Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#define N 100005
int n,m,R,ans,d1[N<<2],d2[N<<2];
inline int readint(){
	char c=getchar();
	for(;!isdigit(c);c=getchar());
	int d=0;
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^‘0‘);
	return d;
}
void add1(int l,int r,int o){
	++d1[o];
	if(l!=r){
		int mid=l+r>>1;
		if(R<=mid)add1(l,mid,o<<1);
		if(mid<R)add1(mid+1,r,o<<1|1);
	}
}
void add2(int l,int r,int o){
	++d2[o];
	if(l!=r){
		int mid=l+r>>1;
		if(R<=mid)add2(l,mid,o<<1);
		if(mid<R)add2(mid+1,r,o<<1|1);
	}
}
void query1(int l,int r,int o){
	if(r<=R)ans+=d1[o];else{
		int mid=l+r>>1;
		query1(l,mid,o<<1);
		if(mid<R)query1(mid+1,r,o<<1|1);
	}
}
void query2(int l,int r,int o){
	if(r<=R)ans+=d2[o];else{
		int mid=l+r>>1;
		query2(l,mid,o<<1);
		if(mid<R)query2(mid+1,r,o<<1|1);
	}
}
int main(){
	n=readint(),m=readint();
	memset(d1,0,sizeof d1);
	memset(d2,0,sizeof d2);
	while(m--){
		int opt=readint(),l=readint(),r=readint();
		if(opt==1){
			R=l;
			add1(1,n,1);
			R=r;
			add2(1,n,1);
		}else{
			int Ans=0;
			ans=0;
			R=r;
			query1(1,n,1);
			Ans+=ans;
			ans=0;
			R=l-1;
			if(R)
			query2(1,n,1);
			Ans-=ans;
			printf("%d\n",Ans);
		}
	}
	return 0;
}

[洛谷P2184]贪婪大陆

标签:int()   时间复杂度   query   一个   sdi   clu   for   ++   void   

原文地址:http://www.cnblogs.com/Mrsrz/p/8082331.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!