题目链接:https://ac.nowcoder.com/acm/contest/16/A
- 刚刚看了二维偏序发现还是很简单的,二维偏序可以这样解释,现在平面上存在很多点,询问有多少个点能找到比它大的点,(大可以解释为:两点 p o i n t 1 ( x 1 , y 1 ) point1(x1, y1) point1(x1,y1) , p o i n t 2 ( x 2 , y 2 ) point2(x2, y2) point2(x2,y2) , x 1 < = x 2 x1<=x2 x1<=x2 && y 1 < = y 2 y1<=y2 y1<=y2,这样则说 p o i n t 1 point1 point1小于 p o i n t 2 point2 point2)。
- 如果暴力枚举去寻找复杂度是 n 2 n^{2} n2,但是仔细想想可以先将所有的点按照x升序排序,这样我们将排序后的点按照y值归并排序,这个时候如果两个区间要合并,在左方区间如果有一点 i i i,它的 y y y值小于右方区间某点 j j j的 y y y值,那么肯定可以说点 i i i小于 j j j(因为按照 x x x排序的时候左方区间所有点的 x x x值一定小于等于右方区间点 x x x值)。
- 再仔细想想按照 x x x值升序排序之后可以从后面开始用树状数组维护 y y y值就可以用维护逆序对的方式直接解决了。
写了个归并树来模拟归并排序的过程
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5+100;
struct Node {
int a, b, pos;
bool operator < (const Node &x) const {
if(x.a != a) return a < x.a;
else return b < x.b;
}
}node[maxn];//记录每个点,pos是输入顺序
vector <Node> ve[maxn];//归并树
int n;
bool vis[maxn];//记录当前点是否能找到比它大的点
void init() {
scanf("%d", &n);
for(int i=1;i<=n;i++) {
scanf("%d%d", &node[i].a, &node[i].b);
node[i].pos = i;
}
sort(node+1, node+1+n);
}
void merge(int root) {//用归并树来模拟一个归并排序的过程
int chl = root<<1;
int chr = root<<1|1;
int totl = 0, totr = 0;
while(totl < ve[chl].size() || totr <ve[chr].size()) {
if(totl < ve[chl].size() && totr == ve[chr].size()) {
ve[root].push_back(ve[chl][totl++]);
} else if(totr < ve[chr].size() && totl == ve[chl].size()) {
ve[root].push_back(ve[chr][totr++]);
} else {
int val = ve[chl][totl].b;
int var = ve[chr][totr].b;
if(val <= var) {
vis[ve[chl][totl].pos] = true;
ve[root].push_back(ve[chl][totl++]);
} else {
ve[root].push_back(ve[chr][totr++]);
}
}
}
}
void build_tree(int root, int l, int r) {
if(l == r) {
ve[root].push_back(node[l]);
return ;
}
int mid = l + r >> 1;
build_tree(root<<1, l, mid);
build_tree(root<<1|1, mid+1, r);
merge(root);
}
int main() {
// freopen("1.in.txt", "r", stdin);
init();
build_tree(1, 1, n);//建立归并树
int ans = 0;
for(int i=1;i<=n;i++) {
if(vis[node[i].pos]) ans++;
}
printf("%d\n", ans);
}
直接用树状数组维护,注意离散化一下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5+100;
struct Node {
int a, b, pos;
bool operator < (const Node &x) const {
if(x.a != a) return a < x.a;
else return b < x.b;
}
}node[maxn];
int n, sum[maxn];
vector <int> ve;//用于离散化
void init() {
scanf("%d", &n);
for(int i=1;i<=n;i++) {
scanf("%d%d", &node[i].a, &node[i].b);
ve.push_back(node[i].a);
ve.push_back(node[i].b);
node[i].pos = i;
}
//离散化一下
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
for(int i=1;i<=n;i++) {
node[i].a = int(lower_bound(ve.begin(), ve.end(), node[i].a) - ve.begin() + 1);
node[i].b = int(lower_bound(ve.begin(), ve.end(), node[i].b) - ve.begin() + 1);
}
sort(node+1, node+1+n);
}
int lowbit(int x) {
return x&-x;
}
void add(int x) {
while(x <= ve.size()) {
sum[x]++;
x += lowbit(x);
}
}
int get_sum(int x) {
int Sum = 0;
if(x <= 0 ) return 0;
while(x > 0) {
Sum += sum[x];
x -= lowbit(x);
}
return Sum;
}
int main() {
// freopen("1.in.txt", "r", stdin);
init();
int ans = 0;
for(int i=n;i>0;i--) {
int temp = get_sum(ve.size()) - get_sum(node[i].b);
if(temp > 0) ans++;
add(node[i].b);
}
printf("%d\n", ans);
}