poj之旅——3109

来源:互联网 发布:linux init.d不见了 编辑:程序博客网 时间:2024/06/11 08:37

题目描述:给出n个点的坐标,若四个点恰好处于十字形,则交点加入这n个点,变成n+1个点,继续变化,直至无法变化,求最后的n。


题解:一开始一点头绪都没有,后来借鉴了:点击打开链接

                      用树状数组,要先离散化,按照y轴扫描,若当前点是此列最高的点,则在接下来的点中不断向树状数组中加1,直到最后一个点时加-1。

       具体地解释一下原理:

       1.离散化——这个大家应该都会,sort后用unique或自己手动。

       2.双关键字排序,以列为一号关键字,这时从第一个开始扫描,有三种情况:

           一.当前点是此行的第一个点,则在此行此列以后的bit中+1

           二.当前点是此行的最后一个点,则在此行此列以后的bit中-1

//前两步具体可见树状数组区间询问原理

           三.当前点在此行中间,若其后一点与其不为同一点,则可用bit求出两点行之间的和即可,累计和。

       3.将2中求出的和+n即为最后结果


参考程序:

#include<cstdio>#include<algorithm>#include<cstring>#define maxn 210000using namespace std;struct Chess{int x,y;}a[maxn];int b[maxn],c[maxn];int sum[maxn];int n;bool cmp_x(Chess a,Chess b){if (a.x != b.x)return a.x<b.x;return a.y<b.y;}bool cmp_y(Chess a,Chess b){if (a.y != b.y)return a.y<b.y;return a.x<b.x;}int bit(int i){return i&(-i);}void add(int i,int x){while (i<=n){sum[i]+=x;i+=bit(i);}}int query(int l,int r){int right=0,left=0;l--;while (l>0){left+=sum[l];l-=bit(l);}while (r>0){right+=sum[r];r-=bit(r);}return right-left;}int main(){scanf("%d",&n);for (int i=0;i<n;i++)scanf("%d%d",&a[i].x,&a[i].y);sort(a,a+n,cmp_x);int cnt=1;for (int i=0;i<n;i++){bool flag=false;if (a[i].x != a[i+1].x)flag=true;a[i].x=cnt;if (flag)cnt++;}sort(a,a+n,cmp_y);cnt=1;for (int i=0;i<n;i++){bool flag=false;if (a[i].y != a[i+1].y)flag=true;a[i].y=cnt;if (flag)cnt++;}memset(c,0,sizeof(c));for (int i=0;i<n;i++)if (c[a[i].x]<a[i].y)c[a[i].x]=a[i].y;int result=0;memset(b,0,sizeof(b));for (int i=0;i<n-1;i++){if (b[a[i].x]==0 && a[i].y!=c[a[i].x]){add(a[i].x,1);b[a[i].x]=1;}if (a[i].y==a[i+1].y){if (a[i].x != a[i+1].x)result+=query(a[i].x+1,a[i+1].x-1);}if (b[a[i].x]==1&&a[i].y==c[a[i].x]){b[a[i].x]=0;add(a[i].x,-1);}}printf("%d",result+n);return 0;}


        

1 0
原创粉丝点击