POJ3067 Japan【树状数组】【逆序数】

题目链接:

http://poj.org/problem?id=3067

题目大意:

有两排的城市,一排N个城市,编号为1~N,一排M个城市,编号为1~M。这两排城市之间有K条路。

路都是直线连接,问:这些路,有多少道路是相交的,并且焦点不是城市所在的点,求出交点个数。

思路:

树状数组的思想。参考网上的图,先将所有边(u,v)按u升序排列,如果u相同,则按v升序排列。可

以看出来,路(u1,v1)和路(u2,v2)如果有交点的话,u1 > u2 并且 v1 < v2,或者 u1 < u2 并且

v1 > v2,为了不重复计算,忽略后一种情况。如果排序完之后,可以发现:结果就是右边序列的逆

序数。直接建立树状数组求逆序数即可。

例如题中例子,如上图所示。排完序为:

1 4

2 3

3 1

3 2

交点个数为:0+1+2+2 = 5个。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define LL __int64
using namespace std;
const int MAXN = 1000;

int Tree[MAXN+10];

struct Node
{
    int u,v;
}Edges[MAXN*MAXN];

int cmp(Node a,Node b)
{
    if(a.u != b.u)
        return a.u < b.u;
    else
        return a.v < b.v;
}

int Lowbit(int x)
{
    return x & (-x);
}

void Update(int i,int x)
{
    while(i <= MAXN)
    {
        Tree[i] += x;
        i += Lowbit(i);
    }
}

LL Query(int n)
{
    LL sum = 0;
    while(n > 0)
    {
        sum += Tree[n];
        n -= Lowbit(n);
    }
    return sum;
}

int main()
{
    int T,N,M,K,kase = 0;
    scanf("%d",&T);
    while(T--)
    {
        memset(Tree,0,sizeof(Tree));
        scanf("%d%d%d",&N,&M,&K);
        for(int i = 0; i < K; ++i)
            scanf("%d%d",&Edges[i].u,&Edges[i].v);
        sort(Edges,Edges+K,cmp);
        LL ans = 0;
        for(int i = 0; i < K; ++i)
        {
            ans += i-Query(Edges[i].v);
            Update(Edges[i].v,1);
        }
        printf("Test case %d: %I64d\n",++kase, ans);
    }

    return 0;
}
时间: 2024-11-16 03:52:43

POJ3067 Japan【树状数组】【逆序数】的相关文章

poj3067 Japan(树状数组)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://poj.org/problem?id=3067 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coast and M cities

POJ3067 Japan 树状数组的应用

这题以前做过,用的线段树,现在用树状数组做一次, 题意:给你n个城市在日本左边,m个城市在日本右边,然后k条路,问你这k条路有几个交点,注意城市的序号其实就是一维坐标所在位置,所以就是两条平行的数轴,上面有点,而且之间有连线,问你有多少交点 一开始不好想把,这种题目也就排排序来试试看了,先对要修建的公路进行排序,然后再看这样是否可以更加方便的求出交点的数论,取路的左边点为先决条件从小到大排列,若相等则按照右边点来升序排列,然后以左边点为序号 和value值为1进行插入树状数组,先求出当前已经插入

hdu2838Cow Sorting(树状数组+逆序数)

题目链接:点击打开链接 题意描述:给定一个长度为100000的数组,每个元素范围在1~100000,且互不相同,交换其中的任意两个数需要花费的代价为两个数之和.问如何交换使数组有序,花费的代价最小? 解题思路: 1.显然我们知道,要使一个数组有序至少交换的次数(即必须要交换的次数)为数组中的逆序数 2.由于数组的长度比较大所以我们可以通过树状数组来统计结果 此处需要两个树状数组 第一个:记录小于等于某个值的元素的个数 第二个:记录小于等于某个值的元素的和 代码: #include <cstdio

HDU 4911 (树状数组+逆序数)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4911 题目大意:最多可以交换K次,就最小逆序对数 解题思路: 逆序数定理,当逆序对数大于0时,若ak<ak+1,那么交换后逆序对数+1,反之-1. 设原始序列最小逆序对数=cnt 那么,交换K次的最小逆序对数max(0,cnt-k) 在求原始序列最小逆序对数上,朴素暴力复杂度O(n^2)不可取 有以下两种O(nlogn)的方法: ①排序内计算: 主要是利用归并排序内的特性,即相邻两个归并序列逆序情

树状数组+逆序数与顺序数——HDU 2492

对应HDU题目:点击打开链接 Ping pong Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description N(3N20000) ping pong players live along a west-east street(consider the street as a line segment). Each player has a unique skil

HDU5196--DZY Loves Inversions 树状数组 逆序数

题意查询给定[L, R]区间内 逆序对数 ==k的子区间的个数. 我们只需要求出 子区间小于等于k的个数和小于等于k-1的个数,然后相减就得出答案了. 对于i(1≤i≤n),我们计算ri表示[i,ri]的逆序对数小于等于K,且ri的值最大.(ri对应代码中的cnt数组) 显然ri单调不降,我们可以通过用两个指针扫一遍,利用树状数组计算出r数组. 对于每个询问L,R,我们要计算的是∑i=LR[min(R,ri)−i+1] 由于ri具有单调性,那我们直接在上面二分即可,然后记一个前缀和(s数组).

POJ3067:Japan(树状数组求逆序对)

Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coast and M cities on the West coast (M <= 1000, N <= 1000). K superhighways will be build. C

POJ3067 树状数组+逆序数

设两线段为(x1,y1) ,(x2,y2), 若使两线段相交,需使x1<x2&&y1>y2||x1>x2&&y1<y2. 那么本题就变得很简单了,对东边点x从小到大排序,当x相等时对西边点y从小到大排序,每插入一条线段,就求一下逆序对数.总和即为答案. 代码如下: 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 #define

hdu 5193 分块 树状数组 逆序对

题意: 给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除.求每次修改后逆序对的个数. 限制: 1 <= n,m <= 20000; 1 <= ai <= n 思路: 插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个. 外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力.查找权值个数时,使用树状数组比较方便.内层通过树状数组维护权值. 每次更新即

题解 SP4226 【MSE06H - Japan】(树状数组+逆序对)

原OJ提交点这里 这道题一开始让我很雾...... 不过 思路其实非常清晰:如果i<j a[i].x<a[j].x a[i].y>a[j].y 那么就会产生一个交点 大家画个图就出来了 具体操作也很好实现: 定义一个结构体 x升序排列 当x相同就y升序排列 按照我们的排序方式 把a[i].y踢出来跑树状数组求逆序对就可以了 附上AC代码 #include<cstdio> #include<iostream> #include<cmath> #inclu