0)
题目大意:
小岛上东、西各有一列从北到南依次排列的城市,现在将东边与西边的指定城市之间建造高速公路(不同列之间的城市相连),要求给出交叉点个数(假设没有大于两条以上的道路会交于一点)。
转化:
随着连接的线段越来越多,交点个数应该只增不降,而输入数据给出的顺序已经是一个提示,我们假设第一列城市属于l列,第二列城市属于r列,那么l列输入的顺序是从小到大时,可以保证l列当前城市(假设是城市2)连接到的r列某城市(假设是城市3),一定是在l列当前城市之前的城市(假设是城市1)连接到的r列城市之前(假设是4)才会构成交点。因此,我们只需不断返回连接当前线段的同时又加了几个交点即可。而在l列城市顺序输入(编号从小到大)时,而所加交点个数,正对应连接当前线段时被连接到的r列城市(城市3)到最后一个城市(城市6)之间所有城市的(不包括城市3,所以恰好sum(6)-sum(3),而不用sum(6)-sum(3-1))被连接次数之和。于是问题,似乎变成了求任意区间求和,线段树和树状数组都可以解决。
注意:如果题目中给出的城市编号有0,就像下面这张图,那么我们应当将所有城市编号++,再用树状数组或线段树。
1)
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn=1010;
struct Road{
int l;
int r;
}road[maxn*maxn];//注意,道路是城市个数的乘积,不然Runtime
int c[maxn];
bool cmp(Road a,Road b){
if(a.l<b.l){
return 1;
}
else if(a.l==b.l){
return a.r<=b.r;//cout<<a>=b>>endl;如果相等输出什么?
}
return 0;
}
int Sum(int x){
long long int sum=0;
while(x>0){
sum+=c[x];
x-=(x&(-x));
}
return sum;
}
void Add(int x){
while(x<maxn){
c[x]++;
x+=(x&(-x));
}
}
int main()
{
int t;
scanf("%d",&t);
int kase=0;
while(t--){
kase++;
memset(c,0,sizeof(c));
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<k;i++){
scanf("%d%d",&road[i].l,&road[i].r);
}
sort(road,road+k,cmp);
long long int res=0;
for(int i=0;i<k;i++){
res+=Sum(m)-Sum(road[i].r);
Add(road[i].r);
}
printf("Test case %d: %lld\n",kase,res);
}
}
2)
Description
Input
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