(POJ 3067) Japan (慢慢熟悉的树状数组)

Japan

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 29295   Accepted: 7902

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

看似是一道二分图图论的问题,其实经过一些简单的(大雾)变换之后,就可以转化为树状数组来求解自昨天被辉大神教做人之后,我对树状数组的理解也有了一些加深:0

大体题意:日本有东和西两个岛,从北到南依次标号为1,2,3...然后给出k条边,求出k条边一共有多少交点(注意是两两相交,只要两条线有交点就算一个)。

经过分析之后可以发现如果两条边有交点,就必须满足x1-x2>0&&y1-y2<0或者x1-x2<0&&y1-y2>0;有两个条件,所以我们可以通过将x排序来变为一个条件:即将所有边按x的大小从小到大排序,然后一边遍历,一边维护树状数组。对于边k,在边1到边k-1中寻找y>yk的边,有几条这样的边,那么对于边k,在1~k-1中就有几个与之相交的边。一边维护树状数组,一边更新交点的值,遍历结束后就可求出所有交点的数量。

PS:在排序时,如果x1==x2,那么要按y1<y2的顺序来排,不然在计算与较小y值那条边相交边的数量时,会将x与之相等的边也算进去(因为树状数组只存储y的值)。
#include<iostream>
#include<cstdio>
#include<vector>
#include<set>
#include<map>
#include<string.h>
#include<cmath>
#include<algorithm>
#include<queue>
#define LL long long
#define inf 0x3f3f3f3f

using namespace std;
int n,m,k;

struct de
{
    int x,y;
    bool operator<(const de &other)const
    {
        if(x==other.x)
            return y<other.y;
        return x<other.x;
    }
};

de qiao[500*1010];
LL run[10100]={0};

int lowbit(int i){return i&(-i);}

void update(int i)
{
    while(i<=m)
    {
        run[i]++;
        i+=lowbit(i);
    }
}

LL sum(int i)
{
    LL s=0;
    while(i>0)
    {
        s+=run[i];
        i-=lowbit(i);
    }
    return s;
}

int main()
{
    int t;
    scanf("%d",&t);
    for(int p=1;p<=t;p++)
    {
        scanf("%d%d%d",&n,&m,&k);
        memset(qiao,0,sizeof(qiao));
        memset(run,0,sizeof(run));
        for(int i=1;i<=k;i++)
            scanf("%d%d",&qiao[i].x,&qiao[i].y);
        sort(qiao+1,qiao+1+k);
        LL ans=0;
        for(int i=1;i<=k;i++)
        {
            ans+=sum(m)-sum(qiao[i].y);
            update(qiao[i].y);
        //cout << "ans=" << ans << endl;

        }
        printf("Test case %d: %I64d\n",p,ans);
    }
    return 0;
}
时间: 2024-08-05 02:00:52

(POJ 3067) Japan (慢慢熟悉的树状数组)的相关文章

POJ 2155 Matrix 【二维树状数组】

题目链接:http://poj.org/problem?id=2155 题目大意:给出一个N*N的0矩阵,下面给出两种指令:1. 给出的第一个数据为'C',再给出四个整形数据,x1,y1,y1,y2,对以(x1,y1)(x2,y2)分别为左上角和右下角坐标的矩阵内的元素进行反转(0变1,1变0)         2. 给出的第一个数据为'Q',再给出两个数据,x,y,然后输出此时这个坐标上的元素. 这题用二维树状数组解,树状数组能够对某区间更新所有元素的和,树状数组维护的是c[1][1]到c[i

【poj 2892】Tunnel Warfare 二分+树状数组

Tunnel Warfare Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 7576 Accepted: 3127 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaki

POJ 2155 Matrix【二维树状数组+YY(区间更新,单点查询)】

题目链接:http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 32950   Accepted: 11943 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th col

POJ - 2299 - Ultra-QuickSort = 归并排序 + 逆序对 / 树状数组

http://poj.org/problem?id=2299 求逆序对最简单的绝对不会是树状数组,一定是归并排序(认真),不过树状数组会不会快一点呢?理论上应该是树状数组快一点(假如不进行离散化). #include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<map> #include<set

POJ 2155 Matrix(二维树状数组)

题意:有一个矩阵,每次操作可以是编辑某个矩形区域,这个区域的0改为1,1改为0,每次查询只查询某一个点的值是0还是1.  思路:这道题和一般的树状数组有一点不同,这道题是区间修改,单点查询,而树状数组处理的是单点修改,所以我们可以改一下矩阵里的每一个值代表的意义.可以注意到我们只关注一个点被翻转了奇数次还是偶数次,令矩阵的元素a[i][j]表示矩形区域(1,1)到(i,j)的修改次数,这样我们可以把区间修改转化为四个端点的单点修改,即modify(x2, y2, 1); modify(x1-

POJ 3321 Apple Tree DFS序 + 树状数组

多次修改一棵树节点的值,或者询问当前这个节点的子树所有节点权值总和. 首先预处理出DFS序L[i]和R[i] 把问题转化为区间查询总和问题.单点修改,区间查询,树状数组即可. 注意修改的时候也要按照dfs序修改,因为你查询就是按照dfs查的,所以修改也要用dfs序修改 L[i]是唯一的. #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <

Poj(2352)——Stars(树状数组)

Description Astronomers often examine star maps where stars are represented by points on a plane and each star has Cartesian coordinates. Let the level of a star be an amount of the stars that are not higher and not to the right of the given star. As

POJ 2155 Matrix (2维树状数组)

POJ-Matrix 题意:给你一个n*n矩阵的灯泡,灯泡的初始状态都为0,T次操作,分别是翻转操作:将x1,y1 --- x2, y2的灯泡状态反转 和 查询操作 找出x1, y1位置灯泡的状态. 题解:开一个2维树状数组进行更新操作. 假设我们现在需要翻转A区域内的灯泡, 我们就需要先将ABCD4个区域一起转换,然后再将CB,BD翻转,再将D翻转,这样结束之后就只有A的状态翻转了,所以我们需要先以(x1,y1)为起点更新ABCD区域,再以(x2+1,y1), (x1,y2+1)对BD, CD

【POJ】3378 Crazy Thairs(树状数组+dp+高精)

题目 传送门:QWQ 分析 题意:给个数列,求有多少五元上升组 考虑简化一下问题:如果题目求二元上升组怎么做. 仿照一下逆序对,用树状数组维护一下就ok了. 三元怎么做呢? 把二元的拓展一位就可以了,即把第三个也扔进树状数组 所以这题就渐渐明朗了: 用$ dp[i][x] $表示以$ A[x] $结尾的$ x $元上升组有多少个 那么: $ dp[i][x]=\sum_{j=1}^{i-1} dp[j][x-1] (A[j]<A[i]) $ 其中 $ dp[i][1]=1 $ 因为多了一位大的就