POJ 3067 Japan(树状数组:求逆序)
http://poj.org/problem?id=3067
题意:
水平方向有2n个城市点,他们分别按顺序分布在平行的两条直线上,编号都是从1到n。然后现在在上直线与下直线的两个城市点之间建公路,一共建k条公路。问你这k条公路一共有多少个交点(保证最多只有两条公路会交于同一点)?
分析:
注意题目中两边的岛是这么分布的:
1 2 3 4
1 2 3 4
且一个点最多只有两条边相交,即不可能出现3线共点的情况.
假设现在1 4 是一条边,其他边我们暂时不知道,那么1 4边会有多少个交点呢? 这主要跟左边的1,2,3(蓝色的)这三个数分别延伸了多少条边有关,只要他们3点延伸的边的另一边的点序号>=1,那么该边必然会与边(1,4)交于1点。
所以我们将获得所有边以y坐标从小到大排序,如果y坐标相同,则x坐标小的排在前面。那么我们当前扫描到的xi,yi边有多少个交点?只要看xi前面有多少个xj(j<=i-1)是大于xi的就行。这就是xi的逆序数。
该题就转化为求排序后的x坐标的逆序数之和了。结果要用long long保存。
AC代码:360ms
<span style="font-size:18px;">#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int MAXN=1000; const int MAXM=1000000+1000; int c[MAXN+1];//c[0]是无效的 struct node { int x,y; bool operator <(const node &b)const { return y<b.y||( y==b.y&&x<b.x ); } }nodes[MAXM]; int lowbit(int x) { return x&(-x); } int sum(int x) { int res=0; while(x>0) { res +=c[x]; x-=lowbit(x); } return res; } void add(int x,int v) { while(x<=MAXN) { c[x]+=v; x+=lowbit(x); } } int main() { int T,kase=1; scanf("%d",&T); while(T--) { int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=0;i<k;i++) scanf("%d%d",&nodes[i].x,&nodes[i].y); sort(nodes,nodes+k); memset(c,0,sizeof(c)); long long ans=0; for(int i=0;i<k;i++) { ans += sum(MAXN)-sum(nodes[i].x);//累加逆序 add(nodes[i].x,1); } printf("Test case %d: %I64d\n",kase++,ans); } return 0; }</span>