poj 2352 Stars
依旧感谢:http://blog.csdn.net/zxy_snow/代码几乎都是照着她的敲得。这里是她的新博客:http://www.xysay.com/
题意很简单:给定坐标点(整数),让你统计这个点的左下方有多少个点(行和列的值可以相同),一个坐标至多有一个点。由于数据是有序给出的,整体按行数递增给出,行数相同时列数递增。
解法:对于点(x,y),由于输入有序,只需要统计[0,x]这区间的最大值,然后对x点加1即可。选用线段树或者树状数组。
我用的是线段树。维护一个左闭右开[0,MAXX+1),节点维护很好写。维护一个最大值即可(注意建树的时候节点要+1)。
之前写线段树(其实也没几次)都是用的“点”树,准确说一个基本元素是一个点,根节点的l和r可以相等,现在改用了线段树,基本元素是长度为1的线段。
每次更新节点,我之前的做法是,如果更新[x,y),当[x,y)不等于节点的l,r时,将x,y拆分,换而言之,就是拆分待操作区间去适应节点区间。每次写很繁琐。
更好的做法是,当[x,y)不等于节点的l,r时,将l,r拆分,也就是用节点区间去适应待操作区间,更新、查询时只要x<=l,r<=y即可。
对于左闭右开区间,拆分区间只要
if(l<mid) update(L(f),l,r,value); if(r>mid) update(R(f),l,r,value);
对于l==mid或者r==mid的时候,我很是纠结了一段时间。其实对于左闭右开区间,如果l==mid,那么r一定>mid,反之亦然,上下两个必然只执行一个。
上代码:
query中注释掉的是我最开始的查询,拆分待操作区间去适应节点区间。
#include <iostream> #include <cstdio> #include <vector> #include <cmath> #include <algorithm> #include <utility> #include <cstring> #include <fstream> #include <string> #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) using namespace std; const int MAXX=32004 ;//区间长度 const int MAXN=15004 ; const int MARK=-65535;//标记,必要时可以有多个 struct tnode { int mark,l,r;//mark=-65535 为未标记状态 int mid(){ return (l+r)/2;} int len(){ return (r-l);} bool in(int ll,int rr) { return l >= ll && r <= rr; } int sum; //自行添加特殊数据:{lmax,rmax,max,num...} } node[MAXX<<2]; int level[MAXN],n; void build(int f,int l,int r) { node[f].l=l;node[f].r=r; node[f].sum=node[f].mark=0; if(node[f].len()==1) return; int mid=node[f].mid(); build(L(f),l,mid); build(R(f),mid,r); } void pushDown(int f) { if(node[f].mark) { node[L(f)].mark+=node[f].mark; node[L(f)].sum+=node[f].mark; node[R(f)].mark+=node[f].mark; node[R(f)].sum+=node[f].mark; node[f].mark=0; } } void update(int f,int l,int r,int value) { if(node[f].in(l,r)) { node[f].sum+=value; node[f].mark+=value; } if(node[f].len()==1) return; pushDown(f); int mid=node[f].mid(); if(l<mid) update(L(f),l,r,value); if(r>mid) update(R(f),l,r,value); node[f].sum=node[L(f)].sum+node[R(f)].sum; } int query(int f,int l,int r) { /*if(node[f].l==l&&node[f].r==r) return node[f].sum; if(node[f].len()==1) return 0; pushDown(f); int mid=node[f].mid(); if(r<=mid) return (query(L(f),l,r)); else if(l>=mid) return query(R(f),l,r); else return query(L(f),l,mid)+query(R(f),mid,r); */ if(node[f].in(l,r)) return node[f].sum; pushDown(f); int ans = 0; int mid = node[f].mid(); if( l < mid ) ans += query(L(f),l,r); if( r > mid ) ans += query(R(f),l,r); return ans; } int main(int argc, char* argv[]) { while(scanf("%d",&n)!=EOF) { build(1,0,MAXX-2); memset(level,0,sizeof(level)); int x,y,xx; for(int i=0;i<n;i++) { scanf("%d%d",&x,&y); int tmp=query(1,0,x+1); level[tmp]++; update(1,x,x+1,1); } for(int i=0;i<n;i++) printf("%d\n",level[i]); } }