这题好像是POJ的一道原题... 首先这题我们能够确定如果一条线段被另外一条线段所包含的话,那么那条包含它的线段的左端点一定小于或者等于这个线段。于是我们按照左端点从小到大排序,左端点相同按照右端点从大到小排序,这样就能够保证所有包含第i条线段的线段一定在前面得到了更新。
接着我们就直接要求前面线段的右区间大于改线段,由于用的树状数组,所以用一个数减去这个右端点,所以该右端点就越靠近左边,所以也就能使上树状数组了,需要注意的当两条线段的属性完全一样时,我们要直接把前面的答案赋值给后面的线段,然后再去更新。
代码如下:
#include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <map> using namespace std; int N, c[400005], ret[200005], idx; map<int,int>mp; struct Node { int l, r, NO; bool operator < (Node temp) const { if (l != temp.l) return l < temp.l; return r > temp.r; } }e[200005]; struct High { int h; bool operator < (High temp) const { return h < temp.h; } bool operator == (High temp) const { return h == temp.h; } }H[400005]; int lowbit(int x) { return x & -x; } void add(int x, int val) { for (int i = x; i <= 400000; i += lowbit(i)) { c[i] += val; } } int sum(int x) { int ret = 0; for (int i = x; i > 0; i -= lowbit(i)) { ret += c[i]; } return ret; } int main() { while (scanf("%d", &N) == 1) { memset(c, 0, sizeof (c)); memset(ret, 0, sizeof (ret)); mp.clear(); idx = -1; for (int i = 0; i < N; ++i) { scanf("%d %d", &e[i].l, &e[i].r); e[i].NO = i; H[++idx].h = e[i].l, H[++idx].h = e[i].r; } sort(H, H+idx+1); idx = unique(H, H+idx+1)-H; for (int i = 0; i < idx; ++i) { mp[H[i].h] = idx - i; } sort(e, e + N); for (int i = 0; i < N; ++i) { int pos = mp[e[i].r]; if (i > 0 && e[i].l == e[i-1].l) { if (e[i].r == e[i-1].r) { ret[e[i].NO] = ret[e[i-1].NO]; } else { ret[e[i].NO] = sum(pos); } } else if (i > 0 && e[i].l > e[i-1].l) { ret[e[i].NO] = sum(pos); } else { ret[e[i].NO] = 0; } add( pos, 1 ); } for (int i = 0; i < N; ++i) { if (i == 0) { printf("%d", ret[i]); } else { printf(" %d", ret[i]); } } puts(""); } return 0; }