来源:http://gzhu-101majia.iteye.com/blog/1143065
题目大意:给你很多线段的头S和尾E,问每一条线段中包含了多少个线段,(S和E相同不计在内)。这题先一看,完全不知道什么方法,感觉非常的难办。
但是!树状数组可以轻松解决这个问题!!!首先,将她们线段的s和e当做是(s,e)一个点,这样子把所有点画出来,你就会发现一个很神奇的现象,题目要求就会变成:问每一个点的左上角有多少个点?
!!!这样不就和那题最简单的stars一样吗???!!!
stars那题是问左下角有多少个点,而这题是问左上角,而且点不是有序排好的,所以有些不同,特殊处理一下就可以。
如果正常做,那个y是递增的,所以sum和update那个方向就会相反了,这个其实没什么所谓,一样的,排序的时候先y由大到小排,y相同时x由小到大排,这样小小的处理,就变成stars那题了!!!
还有一点忘了,这题也是需要离散化的,离散化很重要很强大!!!
就这样!走过路过不要错过!!!
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
#define N 100010
struct Node {
int id;
int first;
int second;
};
Node pos[N];
int n;
int A[N];
int result[N];
int lowbit(int x) {
return x & (-x);
}
void add(int x, int m) {
while(x < N) {
A[x] += m;
x += lowbit(x);
}
}
int sum(int end) {
int result = 0;
while(end > 0) {
result += A[end];
end -= lowbit(end);
}
return result;
}
bool cmp(Node l, Node r) {
if (l.second != r.second) return l.second > r.second;
else return l.first < r.first;
}
int main () {
while(cin>>n && n != 0) {
for (int i = 1; i <= n; i++) {
scanf("%d %d", &pos[i].first, &pos[i].second);
pos[i].id = i;
pos[i].first += 1;
pos[i].second += 1;
}
memset(A, 0, sizeof(A));
memset(result, 0, sizeof(result));
sort(pos+1, pos+n+1, cmp);
result[pos[1].id] = sum(pos[1].first);
add(pos[1].first, 1);
for (int i = 2; i <= n; i++) {
if (pos[i].first == pos[i-1].first &&
pos[i].second == pos[i-1].second) {
result[pos[i].id] = result[pos[i-1].id];
}
else
result[pos[i].id] = sum(pos[i].first);
add(pos[i].first, 1);
}
/*
for (int i = 1; i <= n; i++) {
printf("%d ", A[i]);
}
printf("\n");
*/
for (int i = 1; i < n; i++) {
printf("%d ", result[i]);
}
printf("%d\n", result[n]);
}
return 0;
}