4237: 稻草人

4237: 稻草人

https://www.lydsy.com/JudgeOnline/problem.php?id=4237

分析:

  CDQ分治+单调栈。

  首先按照x排序,每次分治,考虑左边一个点和多少个右边的点可以有贡献。CDQ的过程中,按照y从大到小排序。

  左右两边的y都是从大到小的,所以对于每个左边点,先把y比它大的加上,然后在这些点中维护一个x递增的栈(每个点在上一个点的右下方,如果一个点的x大于下一个点,那么这个点是没有用的,下一个点y小,x小,在其左下方,能遮住它)。

  对于左边的点,维护一个x递减的栈。这个栈的意义是上一个点对栈顶的点有限制(上一个点的x大,y大,所以在其左上方)。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 #include<stack>
12 #define fi(s) freopen(s,"r",stdin);
13 #define fo(s) freopen(s,"w",stdout);
14 using namespace std;
15 typedef long long LL;
16 
17 inline int read() {
18     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
19     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
20 }
21 
22 const int N = 200005;
23 
24 int n;
25 struct Node{
26     int x, y;
27     Node() {}
28     Node(int _x,int _y) { x = _x, y = _y; }
29 }A[N], B[N], sk1[N], sk2[N];
30 int top1, top2;
31 LL Ans;
32 
33 bool operator < (const Node &A, const Node &B) {
34     return A.x < B.x;
35 }
36 
37 int find(int k) {
38     int L = 1, R = top2 + 1, res = top2 + 1;
39     while (L <= R) {
40         int mid = (L + R) >> 1;
41         if (sk2[mid].y < k) res = mid, R = mid - 1; // sk中y是递减的
42         else L = mid + 1;
43     }
44     return res;
45 }
46 
47 void CDQ(int l,int r) {
48     if (l >= r) return ;
49     int mid = (l + r) >> 1;
50     CDQ(l, mid); CDQ(mid + 1, r);
51     
52     top1 = 0, top2 = 0;
53     int i = l, j = mid + 1, k;
54     for (i=l; i<=mid; ++i) {
55         while (top1 && sk1[top1].x < A[i].x) top1--; // x单调递减 
56         sk1[++top1] = A[i];
57         while (j<=r && A[j].y >= A[i].y) {
58             while (top2 && sk2[top2].x > A[j].x) top2 --; // x单调递增
59             sk2[++top2] = A[j ++]; 
60         }
61         if (top1 == 1) Ans += top2;
62         else Ans += top2 - find(sk1[top1-1].y) + 1;
63     }
64     i = l, j = mid + 1, k = l;
65     while (i <= mid && j <= r) {
66         if (A[i].y > A[j].y) B[k++] = A[i ++];
67         else B[k++] = A[j ++];
68     }
69     while (i <= mid) B[k ++] = A[i ++];
70     while (j <= r) B[k ++] = A[j ++];
71     for (i=l; i<=r; ++i) A[i] = B[i];
72 } 
73 
74 int main() { 
75     n = read();
76     for (int i=1; i<=n; ++i) {
77         int x = read(), y = read();
78         A[i] = Node(x, y);
79     }
80     sort(A + 1, A + n + 1);
81     CDQ(1, n);
82     cout << Ans;
83     return 0;
84 }

 

posted @ 2018-09-27 22:33  MJT12044  阅读(292)  评论(0编辑  收藏  举报