您的位置:首页 > 其它

poj3067 树状数组解决二维逆序对

2019-08-09 09:17 85 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_43279710/article/details/98938256

一直在学习二维逆序对的解决方法,然后并没有搞明白,这是第一道自己搞出来的模板题。

POJ3067 JAPAN
题解:
设东部的城市为eie_iei​,西部的城市为wiw_iwi​,那么如果连接e1e_1e1​w2w_2w2​和连接e2e_2e2​w1w_1w1​的两条道路想形成交叉,必然有当e1&lt;e2e_1 &lt; e_2e1​<e2​时,w1& 3ff7 ;gt;w2w_1 &gt; w_2w1​>w2​,也就是说,题意所求的交叉数量一定是在eee有序的情况下,求www的逆序对数,所以我们先对eee排序,在用树状数组对www求逆序对数即可。

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: