Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 6854 | Accepted: 2211 |
Description
Input
Output
Sample Input
3 1 2 0 3 3 4 0
Sample Output
1 0 0
题目大意:给你很多线段的头S和尾E,问每一条线段中包含了多少个线段,(S和E相同不计在内)。这题先一看,完全不知道什么方法,感觉非常的难办。
但是!树状数组可以轻松解决这个问题!!!首先,将她们线段的s和e当做是(s,e)一个点,这样子把所有点画出来,你就会发现一个很神奇的现象,题目要求就会变成:问每一个点的左上角有多少个点?
!!!这样不就和那题最简单的stars一样吗???!!!
stars那题是问左下角有多少个点,而这题是问左上角,而且点不是有序排好的,所以有些不同,特殊处理一下就可以。
如果正常做,那个y是递增的,所以sum和update那个方向就会相反了,这个其实没什么所谓,一样的,排序的时候先y由大到小排,y相同时x由小到大排,这样小小的处理,就变成stars那题了!!!
还有一点忘了,这题也是需要离散化的,离散化很重要很强大!!!
就这样!走过路过不要错过!!!
链接:http://poj.org/problem?id=2481
代码:
#include <iostream> #include <stdio.h> #include <memory.h> #include <algorithm> using namespace std; struct node { int x, y, id; }a[100005]; int n, b[100005], val[100005]; bool cmp1(node a, node b) //排序很重要!!! { if(a.y != b.y) return a.y > b.y; //先由大到小排y return a.x < b.x; //y相同,x由小到大排 } int lowbit(int i) { return i&(-i); } void update(int i, int x) { while(i <= 100005) { b[i] += x; i += lowbit(i); } } int sum(int i) { int sum = 0; while(i > 0) { sum += b[i]; i -= lowbit(i); } return sum; } int main() { int i; while(scanf("%d", &n), n) { memset(b, 0, sizeof(b)); memset(val, 0, sizeof(val)); for(i = 0; i < n; i++) { scanf("%d %d", &a[i].x, &a[i].y); a[i].id = i; a[i].x++; a[i].y++; //x与y都有可能为0,所以都++ } sort(a, a+n, cmp1); val[a[0].id] = sum(a[0].x); //val[]代表各点的sum() update(a[0].x, 1); for(i = 1; i < n; i++) { if(a[i].x == a[i-1].x && a[i].y == a[i-1].y) //若两区间相等 val[a[i].id] = val[a[i-1].id]; //该值等于上一个的值 else val[a[i].id] = sum(a[i].x); update(a[i].x, 1); //更新该点x值 } printf("%d", val[0]); for(i = 1; i < n; i++) { printf(" %d", val[i]); } printf("\n"); } return 0; }