poj 3067 交叉对 树状数组求逆序数

来源:互联网 发布:反称矩阵的性质 编辑:程序博客网 时间:2024/06/07 05:19

题意:

左边n个数,右边m个数, 按顺序排号。

给他们之间的连通关系。

然后求他们总共有几个交叉点。

如:

1       4

2       3

3       2 ,1   

4      

这张图画出来有5个交叉点。


解析:

将对应关系的x排序,余下的数找逆序对的个数就是所求的交叉点了。

难点就在这个转换。


代码:

#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <climits>#include <cassert>#define LL long long#define lson lo, mi, rt << 1#define rson mi + 1, hi, rt << 1 | 1using namespace std;const int maxn = 1000000 + 10;const int inf = 0x3f3f3f3f;const double eps = 1e-8;const double pi = acos(-1.0);const double ee = exp(1.0);int n, m, k;int c[maxn];int lowbit(int x){    return x & -x;}void update(int x, int num){    while (x <= m)    {        c[x] += num;        x += lowbit(x);    }}int query(int x){    int res = 0;    while (x)    {        res += c[x];        x -= lowbit(x);    }    return res;}struct Node{    int x, y;} a[maxn];bool cmp(Node a, Node b){    if (a.x == b.x)        return a.y < b.y;    return a.x < b.x;}int main(){#ifdef LOCAL    freopen("in.txt", "r", stdin);#endif // LOCAL    int ncase;    int ca = 1;    scanf("%d", &ncase);    while (ncase--)    {        scanf("%d%d%d", &n, &m, &k);        for (int i = 1; i <= k; i++)        {            scanf("%d%d", &a[i].x, &a[i].y);        }        sort(a + 1, a + k + 1, cmp);        memset(c, 0, sizeof(c));        LL ans = 0;        for (int i = 1; i <= k; i++)        {            update(a[i].y, 1);            ans = ans + i - query(a[i].y);        }        printf("Test case %d: %lld\n", ca++, ans);    }    return 0;}


0 0
原创粉丝点击