描述
永恒和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; }