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. Cities on each coast
are numbered 1, 2, ... from North to South. Each superhighway is straight line and connects city on the East coast with city of the West coast. The funding for the construction is guaranteed by ACM. A major portion of the sum is determined by the number of
crossings between superhighways. At most two superhighways cross at one location. Write a program that calculates the number of the crossings between superhighways.

Input

The input file starts with T - the number of test cases. Each test case starts with three numbers – N, M, K. Each of the next K lines contains two numbers – the numbers of cities connected by the superhighway. The first one is the number of the city on the
East coast and second one is the number of the city of the West coast.

Output

For each test case write one line on the standard output:

Test case (case number): (number of crossings)

Sample Input

1
3 4 4
1 4
2 3
3 2
3 1

Sample Output

Test case 1: 5

Source

Southeastern Europe 2006

题意:

两边分别有n,m个点,每边点的编号从上到下位1,2,3。。。

现在有K条边连接两边的点,最多只有两条边相交于一点而不会出现三条边以上交于一点的状况,问一共有几个交点

思路:

相交的情况必然是在在Li<Lj的情况下,Ri>Rj

所以在对L,R排序之后,只需要看R里面逆序数的多少即可

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <list>
#include <algorithm>
#include <climits>
using namespace std;

#define lson 2*i
#define rson 2*i+1
#define LS l,mid,lson
#define RS mid+1,r,rson
#define UP(i,x,y) for(i=x;i<=y;i++)
#define DOWN(i,x,y) for(i=x;i>=y;i--)
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define LL long long
#define N (1005*1005)
#define INF 0x3f3f3f3f
#define EXP 1e-8
#define lowbit(x) (x&-x)
const int mod = 1e9+7;

struct node
{
    int l,r,id;
} a[N];
int n,c[N],x,y;

int cmp(node a,node b)
{
    if(a.l!=b.l)
        return a.l<b.l;
    return a.r<b.r;
}

int sum(int x)
{
    int ret = 0;
    while(x>0)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}

void add(int x,int d)
{
    while(x<=y)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}

LL ans;
int main()
{
    int i,j,k,l,r,t,cas = 1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&x,&y,&n);
        MEM(c,0);
        for(i = 1; i<=n; i++)
        {
            scanf("%d%d",&a[i].l,&a[i].r);
        }
        sort(a+1,a+1+n,cmp);
        ans = 0;
        for(i = 1; i<=n; i++)
        {
            add(a[i].r,1);
            ans+=sum(y)-sum(a[i].r);
        }
        printf("Test case %d: %lld\n",cas++,ans);
    }

    return 0;
}
时间: 2024-10-25 09:11:44

POJ3067:Japan(树状数组求逆序对)的相关文章

POJ 3067 Japan 树状数组求逆序对

题目大意:有两排城市,这两排城市之间有一些路相互连接着,求有多少条路相互交叉. 思路:把所有的路先按照x值从小到大排序,x值相同的按照y值从小到大排序,然后插入边的时候,先找有多少比自己y值小的,这些边的x值一定比自己大,也就是一个逆序对,然后统计起来.记得答案要用long long (__int64) CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorith

【bzoj2789】[Poi2012]Letters 树状数组求逆序对

题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度. 第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母. 输出 一个非负整数,表示最少的交换次数. 样例输入 3 ABC BCA 样例输出 2 题解 树状数组求逆序对 一个结论:将序列A通过交换相邻元素变换为序列B,需要的最小次数为A中

Day2:T4用树状数组求逆序对

T4: 用树状数组求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I B[J]>=B[I] 之后就是求逆序对的事情了 然后这里学一下用树状数组的方法 原理是:树状数组是用来求区间和的是吧 就是按权值的区间统计那么可以BIT维护...然后扫一遍 也就是计算有多少个逆序对 按权值的区间统计就是记录数的个数

蓝桥杯小朋友排队(树状数组求逆序对)

居然存在身高为0的数据... 树状数组求逆序对原理: add(h[j],1); //将身高为h[j]的数据的出现次数加1 sum(h[j]);//求i<j 且 h[i] <=h[j] 的数据出现次数之和  那么 i-sum(h[j]) 为 i > j 且 h[i] > h[j] 数据的出现次数之和 即为 逆序对数 #include"cstdio" #include"cstring" #define lowbit(i) i&(-i) u

树状数组求逆序对

给定n个数,要求这些数构成的逆序对的个数.除了用归并排序来求逆序对个数,还可以使用树状数组来求解.树状数组求解的思路:开一个能大小为这些数的最大值的树状数组,并全部置0.从头到尾读入这些数,每读入一个数就更新树状数组,查看它前面比它小的已出现过的有多少个数sum,然后用当前位置减去该sum,就可以得到当前数导致的逆序对数了.把所有的加起来就是总的逆序对数.题目中的数都是独一无二的,这些数最大值不超过999999999,但n最大只是500000.如果采用上面的思想,必然会导致空间的巨大浪费,而且由

hdu5792 World is Exploding(多校第五场)树状数组求逆序对 离散化

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5792 题目描述:给你n个值,每个值用A[i]表示,然后问你能否找到多少组(a,b,c,d)四个编号,四个编号互不相同,然后a < b, c < d,a代表的值小于b代表的值,c代表的值大于d代表的值. 解题思路:先考虑a和b这两个编号,遍历每一个编号作为b,然后找到b前面有多少个小于b的值,就是对于这一个编号b合理的编号a,对于每一组a和b,就可以考虑c和d,能够满足条件c和d的很显然就是除去a和

hdu1394Minimum Inversion Number树状数组求逆序对水题

//ans[i]=ans[i-1]+(n+1)-2*num[i] //num[i]为输入时的数据 //ans[i]为m=i时的逆序数 //用树状数组求ans[0]的逆序对 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=5010; int num[maxn]; int tree[maxn]; int lowbit(int i) { retu

hdu5147 Sequence II树状数组求逆序对

//用树状数组求出在b前面比b小的数的个数 //然后求b后面的顺序对的个数, //枚举b可得quad //由于数列是从1到n的所有数 //那么(n-num[j])-(j-1-totol[j])即为第j个数之后比j大的数的个数 //其中num[j]表示第j个数,total[j]表示在j之前比j小的数的个数 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int

HDU 1394 Minimum Inversion Number (树状数组求逆序对)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题目让你求一个数组,这个数组可以不断把最前面的元素移到最后,让你求其中某个数组中的逆序对最小是多少. 一开始就求原来初始数组的逆序对,树状数组求或者归并方法求(可以看<挑战程序设计>P178),然后根据最前面的元素大小递推一下每次移到最后得到的逆序数,取最小值. 1 #include <iostream> 2 #include <cstdio> 3 #include