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

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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 02:49:33

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

树状数组与线段树

一:树状数组 树状数组是对一个数组改变某个元素和求和比较实用的数据结构.两中操作都是O(logn). 需求:有时候我们需要频繁地求数组的前k项和或者求数组从小标i到j的和,这样每次最坏情况下的时间复杂度就会为O(N),这样效率太低了.而树状数组主要就是为了解决这样一个问题.树状数组在求和及修改都可以在O(lgN)时间内完成. 树状数组需要额外维护一个数组,我们设为C[N],原数组为A[N], 其中每个元素C[i]表示A[i-2^k+1]到A[i]的和,这里k是i在二进制时末尾0的个数.注意通过位

3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Status] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a b c或2 a b

HDU 1566 Color the ball(树状数组or线段树)

Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11387    Accepted Submission(s): 5680 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"

BZOJ 3295 [Cqoi2011]动态逆序对 树状数组套线段树

题意:链接 方法:树状数组套线段树 解析: 这题基本上写的都是什么CDQ点分治,主席树之类的,然而这我都并不会,所以写了一发平衡树套线段树想卡时卡过去,然而我并没有得逞,T的不要不要的,这里用平衡树套线段树的方法参见我的题解:排队.这道题比那道更要简单. 然后我就打算弃坑了~不过看140142做这道题做的热火朝天的,还是打算回来做一下,yy下树状数组套线段树,然后去看hz的题解,只看懂他写理论部分了,代码部分不知所云,所以还是还是得yy.引用理论部分. 删除某个数,只要统计它之前还存在的比它大的

浅谈二维中的树状数组与线段树

一般来说,树状数组可以实现的东西线段树均可胜任,实际应用中也是如此.但是在二维中,线段树的操作变得太过复杂,更新子矩阵时第一维的lazy标记更是麻烦到不行. 但是树状数组在某些询问中又无法胜任,如最值等不符合区间减法的询问.此时就需要根据线段树与树状数组的优缺点来选择了. 做一下基本操作的对比,如下图. 因为线段树为自上向下更新,从而可以使用lazy标记使得矩阵的更新变的高校起来,几个不足就是代码长,代码长和代码长. 对于将将矩阵内元素变为某个值,因为树状数组自下向上更新,且要满足区间加法等限制

[BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过128MB = = 嗯就是这样,代码长度= =我写了260行......Debug了n小时= = 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #in

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin

HDU 1166 敌兵布阵 (我的树状数组加线段树点修改模板)

思路:本题因为是点修改,所以我们可以用线段树或者是树状数组了.线段树的基本操作我在我的代码中会具体体现,关键是要理解下面这幅图,具体的思想大家可以去看看其他的资料 线段树AC代码: #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; #define N 50005 int num

【POJ】1990-MooFest(树状数组or线段树)

树状数组和线段树的解法比较,感觉不论在内存还是时间上都是树状数组占优 大题思路对 v从小到大进行排序,之后找之前的(也就是比v小的坐标) v * sum(abs(xi - x)) 这样的话 abs无法处理,我们用另外一个树状数组记录在x ~ y区间牛的个数,之前那个记录在x ~ y区间内牛的坐标和 Accepted 484 79 C++ 1131   树状数组代码: #include<cstdio> #include<algorithm> #include<cstring&g