vijos 1066 弱弱的战壕

描述

永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b。

mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒ftING...@_@)。

但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT)。这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队。

战壕都有一个保护范围,同它的攻击范围一样,它可以保护处在它左下方的战壕。所有处于它保护范围的战壕都叫做它的保护对象。这样,永恒就必须找到mx的战壕中保护对象最多的点,从而优先消灭它。

现在,由于永恒没有时间来计算,所以拜托你来完成这个任务:

给出这n个战壕的坐标xi、yi,要你求出保护对象个数为0,1,2……n-1的战壕的个数。

格式

输入格式

第一行,一个正整数n(1<=n<=15000)
接下来n行,每行两个数xi,yi,代表第i个点的坐标
(1<=xi,yi<=32000)
注意:可能包含多重战壕的情况(即有数个点在同一坐标)

输出格式

输出n行,分别代表保护对象为0,1,2……n-1的战壕的个数。

样例1

样例输入1[复制]

5
1 1
5 1
7 1
3 3
5 5

样例输出1[复制]

1
2
1
1
0
 
   

树状数组,对X排下序之后以每个点的y进行操作。如果在某次算出sum(y)之后,肯定就是他的等级。因为在它之前的点都是x比它小或者和它相等,但是y没他大的。

 
 
   
 
   
 
   
#include <cstdio>
#include <cstring>
#include <map>
#include <cmath>
#include <queue>
#include <string>
#include <stack>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define abs(x) ((x)>0?(x):-(x))
#define __max(a,b) ((a)>(b)?(a):(b))
#define __min(a,b) ((a)<(b)?(a):(b))
#define rep(i,repstt,repend) for(int i=repstt;i<repend;i++)
#define erep(i,repstt,repend) for(int i=repstt;i<=repend;i++)
#define inf 0x7f//2147483647
#define iinf 0x7fffffff
#define PI acos(-1.0)
#define NOBUG puts("No_Bug_Hear");
#define STOP system("pause");
#define FOUT freopen("out.txt","w",stdout);
#define FIN freopen("in.txt","r",stdin);
#define OUTCLOSE fclose(stdout);
#define INCLOSE fclose(stdin);
#define INIT(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;

struct bat{
	int x,y;
}f[15003];
bool cmp(bat xx,bat yy){
	return (xx.x==yy.x)?(xx.y<yy.y):(xx.x<yy.x);
}
int n,ans[15003],c[32003];
int lowbit(int x){
	return x&(-x);
}
int trsum(int x){
	int ret=0;
	while(x){
		ret+=c[x];
		x-=lowbit(x);
	}
	return ret;
}
void update(int x,int dx){
	while(x<32003){
		c[x]+=dx;
		x+=lowbit(x);
	}
	return ;
}
int main(){
	//FIN
	//FOUT
	while(cin>>n){
		INIT(ans,0);
		erep(i,1,n)
			scanf("%d%d",&f[i].x,&f[i].y);
		sort(f+1,f+1+n,cmp);
		erep(i,1,n){
			ans[trsum(f[i].y)]++;
			update(f[i].y,1);
		}
		erep(i,0,n-1)
			printf("%d\n",ans[i]);
	}
	//INCLOSE
	//OUTCLOSE
	return 0;
}

--------------------------------------------------------------------------------------

昨天又做了一个线段树版本,因为学了线段树。

我的启蒙线段树题是这样:给出一些线段,然后多次询问,某个点x被压在几条给出的线段下。

 

 然后这题,是要我们求每次有一个新的点加入时,比它小的y有几个,因为,先对X从小到大排序以后,每次加入一个y,之前比它小的y保证x和y都小于它,个数就是这个星星的等级这就可以这样,一个1-32000的线段,每次加入一个y,就等于我昨天做的那题加入了一个[y,32000]的线段

然后每次看比y少的点有几个,就是它当前被压在几条线段下

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct node{
	int r,l,v;
}tr[100000];//要是总维护范围的3倍以上才行
struct A{
	int x,y;
}f[15002];
bool cmp(A a,A b){
	return (a.x==b.x)?(a.y<b.y):(a.x<b.x);
}
void build_tree(int step,int lf,int rt){
	tr[step].v=0;
	tr[step].l=lf;
	tr[step].r=rt;
	if(lf==rt)	return ;
	int mid=(lf+rt)/2;
	build_tree(step*2,lf,mid);
	build_tree(step*2+1,mid+1,rt);
}
void insert(int delta,int st,int ed,int step){
	int mid=(tr[step].l+tr[step].r)>>1;
	if(tr[step].l==st&&tr[step].r==ed){
		tr[step].v+=delta;
		return ;
	}else if(tr[step].r==tr[step].l){
		return ;
	}else if(ed<=mid){
		insert(delta,st,ed,step*2);
	}else if(st>mid){
		insert(delta,st,ed,step*2+1);
	}else{
		insert(delta,st,mid,step*2);
		insert(delta,mid+1,ed,step*2+1);
	}
	return ;
}
int query(int x,int step){
	if(tr[step].l==tr[step].r){
		return tr[step].v;
	}
	int mid=(tr[step].l+tr[step].r)>>1;
	return tr[step].v+((x<=mid)?query(x,step*2):query(x,step*2+1));
}
int main(){
	int n,ans[15003];
	while(scanf("%d",&n)==1){
		memset(ans,0,sizeof(ans));
		build_tree(1,0,32002);
		for(int i=0;i<n;i++)
			scanf("%d%d",&f[i].x,&f[i].y);
		sort(f,f+n,cmp);
		for(int i=0;i<n;i++){
			ans[query(f[i].y,1)]++;
			insert(1,f[i].y,32002,1);
		}
		for(int i=0;i<n;i++)
			printf("%d\n",ans[i]);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值