一直在学习二维逆序对的解决方法,然后并没有搞明白,这是第一道自己搞出来的模板题。
POJ3067 JAPAN
题解:
设东部的城市为
e
i
e_i
ei,西部的城市为
w
i
w_i
wi,那么如果连接
e
1
e_1
e1
w
2
w_2
w2和连接
e
2
e_2
e2
w
1
w_1
w1的两条道路想形成交叉,必然有当
e
1
<
e
2
e_1 < e_2
e1<e2时,
w
1
>
w
2
w_1 > w_2
w1>w2,也就是说,题意所求的交叉数量一定是在
e
e
e有序的情况下,求
w
w
w的逆序对数,所以我们先对
e
e
e排序,在用树状数组对
w
w
w求逆序对数即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 10100;
int n, m, k;
ll num[N], c[N];
struct road{
ll e, w;
}r[1010100];
bool cmp(road a, road b){
if(a.e != b.e)
return a.e < b.e;
return a.w <= b.w;
}
void add(int x, int y){
for(;x <= m; x += x & -x) c[x]+=y;
}
ll ask(int x){
ll ans = 0;
for(;x;x -= x &-x) ans+=c[x];
return ans;
}
int main(){
int t;
scanf("%d", &t);
int cas = 0;
while(t--){
scanf("%d%d%d",&n,&m,&k);
memset(num, 0, sizeof(num));
memset(c, 0, sizeof(c));
for(int i = 1;i <= k; i++){
scanf("%lld%lld", &r[i].e, &r[i].w);
}
sort(r+1, r+k+1, cmp);
ll ans = 0;
for(int i = k; i; i--){
ans += ask(r[i].w - 1);
add(r[i].w, 1);
}
printf("Test case %d: %lld\n", ++cas, ans);
}
return 0;
}