您的位置:首页 > 其它

树状数组水题小结 Poj 2352 + 2481 + 3067

2013-07-18 09:54 381 查看
Poj 2352 Stars

题目链接:http://poj.org/problem?id=2352

题意:在输入的星星中统计出每颗星星的左下角的星星数(包括正左与正下),称为一个星星的等级,输出每个等级下的星星数.

思路:由于输入时有序:即优先y坐标升序,然后x升序,相当于每输入一个新的数据都不会对之前输入的星星的等级产生影响,也即当前横坐标比x小的星星的数量就是当前星星的等级

#include <cstdio>
#include <cstring>

int n;
int bit[32010],level[15005];

int lowbit (int x)
{
    return x&(-x);
}

void Update (int k)
{
    while (k<=32010)
	{
		bit[k]+=1;
		k+=lowbit(k);
	}
}

int Cal (int k)
{
	int sum=0;
    while (k>0)
	{
		sum+=bit[k];
		k-=lowbit(k);
	}
    return sum;
}

int main ()
{
	while (~scanf("%d",&n))
	{
		memset(bit,0,sizeof(bit));
		memset(level,0,sizeof(level));
		int i,x,y;
		for (i=1;i<=n;i++)
		{
			scanf("%d%d",&x,&y);
			Update (++x);        //树状数组下标从1开始
			level[Cal(x)-1]++;
		}
		for (i=0;i<n;i++)
			printf("%d\n",level[i]);
	}
	return 0;
}


Poj 2481 Cows

题意:有N头牛 它们每个都有一个领域[S,E] 如果 Si <= Sj and Ej <= Ei ,说明i牛比j牛强壮 求对每头牛而言 有多少牛比它强壮

思路: 按e大到小排序,然后以s作为标记用以更新大于s的牛会有多少个

也就是si<=sj的时候就可以统计sj前面有多少头牛了

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;

const int N=100005;

struct Node
{
    int x,y,id;
}data
;

int n,xmax;             //xmax记录x的最大值,减少更新树状数组时的运行次数
int bit
,ans
;

int lowbit (int x)
{
    return x&(-x);
}
/*
int cmp(const void *a,const void *b)
{
	if (((Node*)a)->y == ((Node*)b)->y)
		return ((Node*)a)->x-((Node*)b)->x;            //x的升序
	return ((Node*)b)->y-((Node*)a)->y;                //y的降序
}
*/

bool cmp (Node a,Node b)
{
    if (a.y==b.y)
		return a.x<b.x;  //x降序
    return a.y>b.y;      //优先y升序
}

void Update (int k)
{
    while (k<=xmax)
	{
		bit[k]+=1;
		k+=lowbit(k);
	}
}

int Getsum (int k)
{
    int sum=0;
    while (k>0)
	{
		sum+=bit[k];
		k-=lowbit(k);
	}
	return sum;
}

void Deal ()
{
	int i;
	sort (data+1,data+n+1,cmp);
//	qsort (data+1,n,sizeof(data[0]),cmp);
	Update (data[1].x);          //该点一定最小,其ans数组一定为0,故不需在循环中计算
	for (i=2;i<=n;i++)
	{
		if (data[i].x==data[i-1].x && data[i].y==data[i-1].y)  //遇到重复的直接更新答案,不再计算
			ans[data[i].id]=ans[data[i-1].id];
		else
			ans[data[i].id]=Getsum(data[i].x);
		Update (data[i].x);               //但仍然需要插入
	}
	for (i=1;i<=n;i++)
		printf(i==n?"%d\n":"%d ",ans[i]);
}

int main()
{
    while (scanf("%d",&n) , n)
    {
		memset (bit,0,sizeof(bit));
		memset (ans,0,sizeof(ans));
		for (int i=1;i<=n;i++)
		{
			scanf("%d%d",&data[i].x,&data[i].y);
			data[i].x++;     //树状数组从1开始
			data[i].id=i;
			xmax=max(xmax,data[i].x);
		}
		Deal ();
	}
	return 0;
}


Poj 3067 Japan

题目链接:http://poj.org/problem?id=3067

题意:有两排城市,这两排之间有一些城市之间有连接的道路,给出所有道路,问有多少道路是相交的

思路:设每一条线为(Ni,Mi),将所有的线按照Mi降序排列,Mi相同的话,按照Ni降序排列,最后只处理Ni

每次统计的时候,从1统计到Ni-1.此时,左边的是比Ni小的,右边是比Ni的相应点(即Mi)大的,所以必与该线段有交点。

需要用__int64来记录答案个数

#include <cstring>
#include <algorithm>
using namespace std;

struct Node
{
    int x,y;
}data[1000010];

int bit[1005];
int N,M,K;

int lowbit(int x)
{
	return x&(-x);
}

void Update (int k)
{
	while(k<=N)
	{
		bit[k]+=1;
		k+=lowbit(k);
	}
}

int GetSum (int k)
{
	int sum=0;
	while (k>0)
	{
		sum+=bit[k];
		k-=lowbit(k);
	}
	return sum;
}

bool cmp (Node a,Node b)
{
	if (a.y==b.y)
		return a.x>b.x;
	return a.y>b.y;
}

int main()
{
	int T;
	scanf("%d",&T);
	for (int Cas=1;Cas<=T;Cas++)
	{
		scanf("%d%d%d",&N,&M,&K);
		memset(bit,0,sizeof(bit));
		int i;
		for (i=1;i<=K;i++)
			scanf("%d%d",&data[i].x,&data[i].y);
		__int64 ans=0;
		sort(data+1,data+K+1,cmp);
		Update (data[1].x);
		for (i=2;i<=K;i++)
		{
			ans+=GetSum(data[i].x-1);
			Update(data[i].x);
		}
		printf("Test case %d: %I64d\n",Cas,ans);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: