AT1225 かかし
好题。
考虑 cdq
分治维护偏序。
按照横坐标递增排序,再按照纵坐标递减归并。
考虑左半边和右半边的点对,对于左半边合法点 ,将右半边纵坐标 的点加入单调栈,同时维护横坐标单增。
对于左半边内部的影响,另用一个单调栈维护,横坐标递减,答案累加时二分右边栈内纵坐标小于左边栈顶纵坐标个数即可。
左边栈: 单减, 单减。
右边栈: 单减, 单增。
时间复杂度 ,这里偷懒用 sort
导致多了个 。
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
#define ha putchar(' ')
#define he putchar('\n')
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void write(ll x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
const int _ = 2e5 + 10;
int n;
ll ans;
struct abc
{
int x, y;
} k[_], t[_];
int t1, s1[_], t2, s2[_];
bool cmp1(abc a, abc b) {return a.x < b.x;}
bool cmp2(abc a, abc b) {return a.y > b.y;}
int erfen(int p)
{
int l = 0, r = t2;
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(k[s2[mid]].y > p) l = mid;
else r = mid - 1;
}
return l;
}
void cdq(int l, int r)
{
if(l == r) return;
int mid = (l + r) >> 1;
cdq(l, mid), cdq(mid + 1, r);
sort(k + l, k + mid + 1, cmp2);
sort(k + mid + 1, k + r + 1, cmp2);
int j = mid + 1; t1 = t2 = 0;
for(int i = l; i <= mid; ++i)
{
while(j <= r && k[i].y < k[j].y)
{
while(t2 && k[s2[t2]].x > k[j].x) t2--;
s2[++t2] = j, j++;
}
while(t1 && k[s1[t1]].x < k[i].x) t1--;
ans += t2;
if(t1) ans -= erfen(k[s1[t1]].y);
s1[++t1] = i;
}
}
signed main()
{
n = read();
for(int i = 1; i <= n; ++i)
k[i].x = read(), k[i].y = read();
sort(k + 1, k + n + 1, cmp1);
cdq(1, n);
write(ans), he;
return 0;
}
/*
10
2 1
3 0
6 3
10 2
16 4
0 8
8 12
11 14
14 11
18 10
15
*/
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122000