BZOJ4237: 稻草人

n<=200000个平面上的点,问有多少对点(i,j)满足Xi<Xj,Yi<Yj,且不存在k使得Xi<Xk<Xj && Yi<Yk<Yj。保证Xi,Yi互不相同。

看起来像一个偏序问题,先按Xi排序然后分治来做,但是那坨长长的东西怎么搞呢?试了若干种方法,不会,看题解。

首先Y这一维是要满足的,所以分治时把左右两边按Y归并排序后来看左边对右边的贡献。但是有诸多情况。。。

实验+总结一下可以观察到下面两个性质:

(1)

两边按y排序(从大到小)后,开两个指针扫一扫可以满足条件Yi<Yj,然而并不是所有的都满足,如上图,存在一些遮拦的点。

由于y是从大到小排序的,可以看一下在左半边把点按y从大到小加进去后会发生什么遮拦情况:

如图,y从大到小将点加入后,左边若是Yi>Yj却Xi<Xj,那么能被i点(A)拦到的点一定能被j点(B)拦到,因此左半边维护一个Xi随Yi减小而减小的栈,即可找到左边点的互相遮拦限制。如上图中,C点需要在右边找到比B点的y小而比C点的y大的来计算答案。

(2)看右边点的互相遮拦:

由于y是从大到小加进去的,新加进的左边的C点的y一定比原来加进的A和B点要小,此时B被A完全拦住。因此右边若Yi>Yj,则必须Xi<Xj,右边维护一个栈即可满足条件3.

两个栈就完了吗?嗯。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<stdlib.h>
 5 //#include<iostream>
 6 using namespace std;
 7 
 8 int n;
 9 #define maxn 200011
10 struct Point
11 {
12     int x,y;
13     bool operator < (const Point &b) const {return x<b.x;}
14 }a[maxn];
15 
16 int ord[maxn],tmpord[maxn];
17 int stal[maxn],topl,star[maxn],topr;
18 #define LL long long
19 LL ans=0;
20 void solve(int L,int R)
21 {
22     if (L==R) {ord[L]=L;return;}
23     const int mid=(L+R)>>1;
24     solve(L,mid);solve(mid+1,R);
25     topl=topr=0;
26     for (int i=L,j=mid+1;i<=mid;i++)
27     {
28         while (j<=R && a[ord[j]].y>a[ord[i]].y)
29         {
30             while (topr && a[star[topr]].x>a[ord[j]].x) topr--;
31             star[++topr]=ord[j++];
32         }
33         while (topl && a[stal[topl]].x<a[ord[i]].x) topl--;
34         stal[++topl]=ord[i];
35         int l=0,r=topr;
36         while (l<r)
37         {
38             const int mid=(l+r+1)>>1;
39             if (a[star[mid]].y>a[ord[i]].y) l=mid;
40             else r=mid-1;
41         }
42         int up=l,down;
43         if (topl==1) down=1;
44         else
45         {
46             l=1,r=topr+1;
47             while (l<r)
48             {
49                 const int mid=(l+r)>>1;
50                 if (a[star[mid]].y<a[stal[topl-1]].y) r=mid;
51                 else l=mid+1;
52             }
53             down=l;
54         }
55         ans+=up-down+1;
56 //        cout<<L<<' '<<R<<' '<<ord[i]<<' '<<ans<<endl;
57     }
58     int i=L,j=mid+1,k=L;
59     while (i<=mid && j<=R)
60     {
61         if (a[ord[i]].y>a[ord[j]].y) tmpord[k++]=ord[i++];
62         else tmpord[k++]=ord[j++];
63     }
64     while (i<=mid) tmpord[k++]=ord[i++];
65     while (j<=R) tmpord[k++]=ord[j++];
66     for (k=L;k<=R;k++) ord[k]=tmpord[k];
67 }
68 
69 int main()
70 {
71     scanf("%d",&n);
72     for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
73     sort(a+1,a+1+n);
74 //    for (int i=1;i<=n;i++) cout<<a[i].x<<' '<<a[i].y<<endl;cout<<endl;
75     solve(1,n);
76     printf("%lld\n",ans);
77     return 0;
78 }
View Code

 

posted @ 2017-11-27 18:31  Blue233333  阅读(329)  评论(3编辑  收藏  举报