每次输出有几条线段能完全覆盖大于自己和hdu5372相反 树状数组或线段树 poj 2481 Cows

来源:互联网 发布:青岛seo公司排名 编辑:程序博客网 时间:2024/06/06 05:38

http://poj.org/problem?id=2481

Cows
Time Limit: 3000MS Memory Limit: 65536KTotal 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

31 20 33 40

Sample Output

1 0 0

Hint

Huge input and output,scanf and printf is recommended.

Source

POJ Contest,Author:Mathematica@ZSU

思路:树状数组
分析:
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;}elsereturn 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 100010struct 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

0 0
原创粉丝点击