题目链接:点击打开链接
又是树状数组的应用 ,花了好长时间。
题目大意:
给你很多线段的头S和尾E,问每一条线段中包含了多少个线段,(S和E相同不计在内)。这题先一看,完全不知道什么方法,感觉非常的难办。
但是!树状数组可以轻松解决这个问题!!!首先,将她们线段的s和e当做是(s,e)一个点,这样子把所有点画出来,你就会发现一个很神奇的现象,题目要求就会变成:问每一个点的左上角有多少个点?
!!!这样不就和那题最简单的stars一样吗???!!!
stars那题是问左下角有多少个点,而这题是问左上角,而且点不是有序排好的,所以有些不同,特殊处理一下就可以。
如果正常做,那个y是递增的,所以sum和update那个方向就会相反了,这个其实没什么所谓,一样的,排序的时候先y由大到小排,y相同时x由小到大排,这样小小的处理,就变成stars那题了!!!
难点在于处理相同区间,对于相同区间,只是把答案直接拷贝过来,并把其加入树状数组,不可以直接在树状数组中求和。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> #include <queue> using namespace std; struct q { int s; int e ; int id; }p[100005]; int a[100005]; int b[100005]; int n; int maxnum; bool cmp (q a ,q b) { if (a.e == b.e ) return a.s < b.s; else return a.e > b.e; } int lowbit(int i) { return i & (-i); } int sum(int i) { int ans = 0; while (i>0) { ans += b[i]; i-=lowbit(i); } return ans; } void update (int i,int v) { while (i <= maxnum + 1) { b[i]+=v; i+=lowbit(i); } } int main () { while (scanf ("%d",&n), n) { maxnum = -1; memset (b,0,sizeof (b)); memset (a,0,sizeof (a)); for (int i=0;i<n;i++) { scanf("%d %d",&p[i].s,&p[i].e); p[i].e++; p[i].s++; p[i].id=i; maxnum = max (maxnum,p[i].s); } sort (p,p+n,cmp); a[p[0].id]=sum(p[0].s); update(p[0].s,1); for (int i=1;i<n;i++) { if (p[i].e == p[i-1].e && p[i].s == p[i-1].s ) { a[p[i].id] = a[p[i-1].id]; } else { a[p[i].id] = sum(p[i].s ); } update(p[i].s ,1); } printf ("%d",a[0]); for (int i=1 ;i<n;i++) printf(" %d",a[i]); printf("\n"); } return 0; }