http://poj.org/problem?id=2481
Cows
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 14762 | Accepted: 4886 |
Description
Farmer John‘s cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in his field is particularly good.
Farmer John has N cows (we number the cows from 1 to N). Each of Farmer John‘s N cows has a range of clover that she particularly likes (these ranges might overlap). The ranges are defined by a closed interval [S,E].
But some cows are strong and some are weak. Given two cows: cowi and cowj, their favourite clover range is [Si, Ei] and [Sj, Ej]. If Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj, we say that cowi is stronger than cowj.
For each cow, how many cows are stronger than her? Farmer John needs your help!
Input
The input contains multiple test cases.
For each test case, the first line is an integer N (1 <= N <= 105), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 105) specifying the start end location respectively of a
range preferred by some cow. Locations are given as distance from the start of the ridge.
The end of the input contains a single 0.
Output
For each test case, output one line containing n space-separated integers, the i-th of which specifying the number of cows that are stronger than cowi.
Sample Input
3 1 2 0 3 3 4 0
Sample Output
1 0 0
Hint
Huge input and output,scanf and printf is recommended.
Source
POJ Contest,Author:[email protected]
思路:树状数组
分析:
1 题目给定n头牛所在的区间,然后问每头牛都有几头牛比它强壮
2 根据题目如果牛i的区间是[Si , Ei],牛j的区间是[Sj , Ej]那么牛i要比牛j强壮的话,那么就有Si <= Sj && Ei >= Ej &&
Ei - Si > Ej - Sj;
3 那么根据上面的条件,我们应该要先对n头牛的区间排序”按照S从小到大,相同S按照E从大到小排序“
4 显然排完序之后我们能够满足Si <= Sj && Ei >= Ej,但是我们应该要注意到Ei - Si > Ej - Sj说明了排完序之后不能够相等
5 我们利用E做树状数组,如果前后两个相当那么直接更新即可
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 100010; struct Node{ int S; int E; int number; bool operator<(const Node& tmp)const{ if(S < tmp.S) return true; else if(S == tmp.S && E > tmp.E) return true; return false; } bool operator==(const Node& tmp)const{ return S == tmp.S && E == tmp.E; } }; Node node[MAXN]; int n; int ans[MAXN]; int treeNum[MAXN]; int lowbit(int x){ return x&(-x); } int getSum(int x){ int sum = 0; while(x){ sum += treeNum[x]; x -= lowbit(x); } return sum; } void add(int x , int val){ while(x < MAXN){ treeNum[x] += val; x += lowbit(x); } } void solve(){ memset(ans , 0 , sizeof(ans)); memset(treeNum , 0 , sizeof(treeNum)); sort(node , node+n); for(int i = 0 ; i < n ; i++){ int id = node[i].E; if(i && node[i] == node[i-1]) ans[node[i].number] = ans[node[i-1].number]; else ans[node[i].number] += i-getSum(id-1); add(id , 1); } printf("%d" , ans[0]); for(int i = 1 ; i < n ; i++) printf(" %d" , ans[i]); puts(""); } int main(){ while(scanf("%d" , &n) && n){ for(int i = 0 ; i < n ; i++){ scanf("%d%d" , &node[i].S , &node[i].E); node[i].number = i; } solve(); } return 0; }
按照s,e中的e从大到小,如果e相等-s从小到大排序。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define nMax 100010 #define Max(a,b) (a>b?a:b) #define Min(a,b) (a<b?a:b) struct COW { int s,e,id; }cow[nMax]; int ans[nMax]; int cnt[nMax]; int maxN = -1; //比较函数,按照e从大到小,s从小到大 int cmp(const void * a, const void * b) { struct COW *c = (struct COW *)a; struct COW *d = (struct COW *)b; if (c->e == d->e) { return c->s - d->s; } else return d->e - c->e; } //树状数组的三个函数,一个是求x的最后一个1的位置,在某一位置增加一个数,求出num以前的所有数的和这三个函数 int lowbit(int x) { return x&(x^(x - 1)); } void add(int pos) { while (pos <= maxN + 1) { ans[pos] ++; pos += lowbit(pos); } } int sum(int num) { int sum = 0; while (num > 0) { sum += ans[num]; num -= lowbit(num); } return sum; } int main() { int n; while (scanf("%d", &n) && n) { maxN = -1; for (int i = 1; i <= n; ++ i) { scanf("%d %d", &cow[i].s, &cow[i].e); cow[i].id = i; maxN = Max(maxN, cow[i].e); } memset(ans, 0, sizeof(ans)); qsort(cow + 1, n, sizeof(cow[0]), cmp); for (int i = 1; i <= n; ++ i) { if (cow[i].s == cow[i - 1].s && cow[i].e == cow[i - 1].e)//相等的话,不计算在内 { cnt[cow[i].id] = cnt[cow[i - 1].id]; } else//否则可以求出覆盖本区间的所有牛的个数,由于排序,只能在前面 cnt[cow[i].id] = sum(cow[i].s + 1); add(cow[i].s + 1);//将本区间的起始点加入到树状数组中 } for (int i = 1; i < n; ++ i) { printf("%d ", cnt[i]); } printf("%d\n", cnt[n]); } return 0; }
思路:线段树+单点更新
分析:
1 题目给定n头牛所在的区间,然后问每头牛都有几头牛比它强壮
2 根据题目如果牛i的区间是[Si , Ei],牛j的区间是[Sj , Ej]那么牛i要比牛j强壮的话那么就有Si <= Sj && Ei >= Ej && Si-Ei != Sj-Ej;
3 那么根据上面的条件,我们应该要先对n头牛的区间排序”按照S从小到大,相同S按照E从大到小排序“,然后就可以利用线段树求了。
4 有一个地方需要注意的是当排完序后相邻的两个相等,那么只须更新不用求和。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 100010 struct Segment{ int x; int y; int number; bool operator==(const Segment &a)const{ if(a.x == x && a.y == y) return true; return false; } }; Segment s[MAXN]; struct Node{ int left; int right; int sum; }; Node node[4*MAXN]; int n; int vis[MAXN]; bool cmp(Segment s1 , Segment s2){ if(s1.x < s2.x) return true; else if(s1.x == s2.x && s1.y > s2.y) return true; return false; } void buildTree(int left , int right , int pos){ node[pos].left = left; node[pos].right = right; node[pos].sum = 0; if(left == right) return; int mid = (left+right)>>1; buildTree(left , mid , pos<<1); buildTree(mid+1 , right , (pos<<1)+1); } int query(int left , int right , int pos){ if(node[pos].left == left && node[pos].right == right) return node[pos].sum; int mid = (node[pos].left+node[pos].right)>>1; if(right <= mid) return query(left , right , pos<<1); else if(left > mid) return query(left , right , (pos<<1)+1); else return query(left , mid , pos<<1)+query(mid+1 , right , (pos<<1)+1); } void update(int index , int pos){ if(node[pos].left == node[pos].right){ node[pos].sum++; return; } int mid = (node[pos].left+node[pos].right)>>1; if(index <= mid) update(index , pos<<1); else update(index , (pos<<1)+1); node[pos].sum = node[pos<<1].sum+node[(pos<<1)+1].sum; } int main(){ while(scanf("%d" , &n) && n){ memset(vis , 0 , sizeof(vis)); for(int i = 0 ; i < n ; i++){ scanf("%d%d" , &s[i].x , &s[i].y); s[i].number = i; } sort(s , s+n , cmp); buildTree(1 , MAXN , 1); for(int i = 0 ; i < n ; i++){ if(i && s[i] == s[i-1]) vis[s[i].number] = vis[s[i-1].number]; else vis[s[i].number] += query(s[i].y , MAXN , 1); update(s[i].y , 1); } printf("%d" , vis[0]); for(int i = 1 ; i < n ; i++) printf(" %d" , vis[i]); printf("\n"); } return 0; }
当前插入的线段能完整覆盖存在的几条线段 树状数组 HDU 5372
Segment Game
http://blog.csdn.net/acm_10000h/article/details/47907605
版权声明:本文为博主原创文章,未经博主允许不得转载。