树状数组(5)

1、POJ 1990 MooFest

http://acm.pku.edu.cn/JudgeOnline/problem?id=1990

枚举的化肯定超时。算法魅力我个人认为在于减少普通算法的重复计算。本题中如果枚举,会不断重复计算每个牛声音小的牛之间的距离差。如果我们知道比当前牛声音小的牛的个数count和距离之和total。那么我们可以利用ans+= 1LL * cow[i].vol* (count * cow[i].x - total + alltotal - total - (i-count-1)*cow[i].x);其中alltotal是距离总和,alltotal- total - (i-count-1)*cow[i].x计算的是距离比他大的牛的距离差, count* cow[i].x- total是距离比他小的距离差。count和total可以用两个树状数组维护。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAX = 20000 + 10;
int n;
struct node
{
	int vol;
	int x;
}cow[MAX];
int c1[MAX], c2[MAX];
bool operator<(const node&a, const node&b)
{
	return a.vol < b.vol || a.vol == b.vol && a.x < b.x;
}
int lowbit(int x)
{
	return x&(-x);
}
void update(int x, int v, int type)
{
	while (x<MAX)
	{
		if (type == 1)
		{
			c1[x] += v;
		}
		else
		{
			c2[x] += v;
		}
		x+=lowbit(x);
	}
}

int getsum(int x, int type)
{
	int sum = 0;
	while (x)
	{
		if (type == 1)
		{
			sum += c1[x];
		}
		else
		{
			sum += c2[x];
		}
		x-=lowbit(x);
	}
	return sum;
}
int main()
{
	int i;
	int count, total, alltotal; 
	__int64 ans;
	while (scanf("%d", &n) == 1)
	{
		alltotal = 0;
		ans = 0;
		memset(c1, 0, sizeof(c1));
		memset(c2, 0, sizeof(c2));
		for (i=1; i<=n; i++)
		{
			scanf("%d%d", &cow[i].vol, &cow[i].x);
		}
		sort(cow+1, cow+n+1);
		for (i=1; i<=n; i++)
		{
			//printf("%d %d\n", cow[i].vol, cow[i].x);
			count = getsum(cow[i].x-1, 1);
			total = getsum(cow[i].x-1, 2);
			ans += 1LL * cow[i].vol * (count * cow[i].x - total + alltotal - total - (i-count-1)*cow[i].x);
			alltotal += cow[i].x;
			update(cow[i].x, 1, 1);
			update(cow[i].x, cow[i].x, 2);
		}
		printf("%I64d\n", ans);
	}
}


2、Hdu 3015 Disharmony Trees

 http://acm.hdu.edu.cn/showproblem.php?pid=3015

跟上题方法相同,只要按它的要求离散化后,按高度降序排序,套用上题二个树状数组的方法即可。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int MAX = 100000 + 10;
int n;
struct node1
{
    int h;
    int x;
    int id;
}tree[MAX];
struct node2
{
    int rankx;
    int rankh;
}rank[MAX];
int c1[MAX], c2[MAX];
bool cmph(const node1&a, const node1&b)
{
    return a.h<b.h;
}
bool cmpx(const node1&a, const node1&b)
{
    return a.x<b.x;
}
bool cmpr(const node2&a, const node2&b)
{
    return a.rankh>b.rankh;
}
int lowbit(int x)
{
    return x&(-x);
}
void update(int x, int v, int type)
{
    while (x<=n)
    {
        if (type == 1)
        {
            c1[x] += v;
        }
        else
        {
            c2[x] += v;
        }
        x+=lowbit(x);
    }
}

int getsum(int x, int type)
{
    int sum = 0;
    while (x)
    {
        if (type == 1)
        {
            sum += c1[x];
        }
        else
        {
            sum += c2[x];
        }
        x-=lowbit(x);
    }
    return sum;
}
int main()
{
    int i;
    int count, total, alltotal, r; 
    __int64 ans;
    while (scanf("%d", &n) == 1)
    {
        alltotal = 0;
        ans = 0;
        memset(c1, 0, sizeof(c1));
        memset(c2, 0, sizeof(c2));
        for (i=1; i<=n; i++)
        {
            scanf("%d%d", &tree[i].x, &tree[i].h);
            tree[i].id = i;
        }
        sort(tree+1, tree+n+1,cmpx);
        r = 1;
        rank[tree[1].id].rankx = 1;
        for (i=2; i<=n; i++)
        {
            if (tree[i].x!=tree[i-1].x)
            {
                r=i;
                rank[tree[i].id].rankx = i;    
            }
            else
            {
                rank[tree[i].id].rankx = r;
            }
        }
        sort(tree+1, tree+n+1,cmph);
        r = 1;
        rank[tree[1].id].rankh = 1;
        for (i=2; i<=n; i++)
        {
            if (tree[i].h!=tree[i-1].h)
            {
                r=i;
                rank[tree[i].id].rankh = i;    
            }
            else
            {
                rank[tree[i].id].rankh = r;
            }
        }
        sort(rank+1, rank+n+1,cmpr);
        for (i=1; i<=n; i++)
        {
            //printf("%d %d\n", rank[i].rankx, rank[i].rankh);
            count = getsum(rank[i].rankx-1, 1);
            total = getsum(rank[i].rankx-1, 2);
            ans += 1LL * rank[i].rankh * (count * rank[i].rankx - total + alltotal - total - (i-count-1)*rank[i].rankx);
            alltotal += rank[i].rankx;
            update(rank[i].rankx, 1, 1);
            update(rank[i].rankx, rank[i].rankx, 2);
        }
        printf("%I64d\n", ans);
    }
}


3、HOJ 2430  Counting the algorithms

 http://acm.hit.edu.cn/hoj/problem/view?id=2430

贪心,如果是两个包含的区间则先删除外边的最优。如果是交叉区间的情况,无论先删哪个,答案都是一样的。所以采取如下策略,从左边向右边,一个一个删除。至于统计动态的两个相邻元素之间的数目,可以使用树状数组。(这段语句引用于:http://blog.csdn.net/hyogahyoga/article/details/8041549

 

/*This Code is Submitted by 1043041006 for Problem 2430 at 2013-04-05 10:23:52*/
#include <stdio.h>
#include <string.h>
#define DEBUGE 0
const int MAX = 100000 * 2 + 10;
int n;
int a[MAX], c[MAX], begin[MAX], end[MAX];
bool flag[MAX];

int lowbit(int x)
{
        return x&(-x);
}
void update(int x, int v)
{
        while (x<=2*n)
        {
                c[x] +=v;
                x+=lowbit(x);
        }
}
int getsum(int x)
{
        int sum = 0;
        while (x)
        {
                sum += c[x];
                x -= lowbit(x);
        }
        return sum;
}
int main()
{
        int i, ans = 0;
        while(scanf("%d", &n) == 1)
        {
                ans = 0;
                memset(flag, 0, sizeof(flag));
                memset(c, 0, sizeof(c));
                for (i=1; i<=2*n; i++)
                {
                        scanf("%d", a+i);
                        if (flag[a[i]])
                        {
                                end[a[i]] = i;
                        }
                        else
                        {
                                begin[a[i]] = i;
                                flag[a[i]] = true;
                        }
                        update(i, 1);
                }
                for (i=1; i<=2*n; i++)
                {
                        #if DEBUGE
                        printf("%d %d\n", begin[a[i]], end[a[i]]);
                        #else
                        if (!flag[a[i]])
                        {
                                continue;
                        }
                        //printf("%d\n", getsum(end[a[i]]-1));
                        ans += getsum(end[a[i]]-1);
                        flag[a[i]] = false;
                        update(begin[a[i]], -1);
                        update(end[a[i]], -1);
                        #endif
                }
                printf("%d\n", ans);
        }
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值