树状数组(6)

1、tju 3243 Blocked Road

 http://acm.tju.edu.cn/toj/showp3243.html

道路形成了一个圆,从一点到令一点,有两条路线可以选择,走弧度较小的和弧度较大的。判断是否连通,我们可以先用j = Getsum(b-1) – Getsum(a – 1),如果j等于(b – a)或者Getsum(n) – j等于(n – (b – a)),那么点a, b联通。代码不见了。

2、SPOJ 227 Ordering the Soldiers

 http://www.spoj.pl/problems/ORDERS/

首先明确树状数组是可以求第k大数的。由于getsum()是递增的,可以用二分求出使得getsum(j)==k的最小的j这道题和正常的树状数组题目相反,给出某点前面比他大的数的个数吗,求出此点。从后往前求,因为从后往前就能确定当前点是第几大的数,假设排在当前点前面比他大的数有一个·,点的个数为5,那么当前点必然为4.我们用树状数组来求第k大数。注意,由于我们可能先前已经删除了一些数,所以我们要找到最小的数使得他成为第k大数。

 

#include <stdio.h>
#include <string.h>
const int MAX = 200000 + 10;

int n;
int c[MAX], a[MAX], ans[MAX];
int lowbit(int x)
{
	return x&(-x);
}

void update(int x, int v)
{
	while (x<=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 find(int v)
{
	int l = 1, r = n, mid, t;
	while (l < r)
	{
		mid = (l + r) >> 1;
		t = getsum(mid);
		if (t < v)
		{
			l = mid + 1;
		}
		else if (t >= v)
		{
			r  = mid;
		}
	}
	return r;
}
int main()
{
	int t, i;
	while (scanf("%d", &t)==1)
	while (t--)
	{
		memset(c, 0, sizeof(c));
		scanf("%d", &n);
		for (i=1; i<=n; i++)
		{
			scanf("%d", a+i);
			update(i, 1);
		}
		for (i=n; i>=1; i--)
		{
			ans[i] = find(i-a[i]);
			update(ans[i], -1);
		}
		printf("%d", ans[1]);
		for (i=2; i<=n; i++)
		{
			printf(" %d", ans[i]);
		}
		puts("");
	}
	return 0;
}



3、hdu 2852 KiKi's K-Number

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

裸的求第k大数;

#include <stdio.h>
#include <string.h>
const int MAX = 100000 + 10;
int m, p, e, a, k;
int c[MAX];
int lowbit(int x)
{
    return x&(-x);
}

void update(int x, int v)
{
    while (x<MAX)
    {
        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()
{
    while (scanf("%d", &m)== 1)
    {
        memset(c, 0, sizeof(c));
        while (m--)
        {
            scanf("%d", &p);
            if (p == 0)
            {
                scanf("%d",&e);
                update(e, 1);
            }
            if (p == 1)
            {
                scanf("%d",&e);
                if (getsum(e) - getsum(e-1) == 0)
                {
                    printf("No Elment!\n");
                }
                else
                {
                    update(e, -1);
                }
            }
            if (p == 2)
            {
                scanf("%d%d", &a, &k);
                int t = getsum(a) +k;
                int l = 1, r=MAX-1, mid;
                while (l<r)
                {
                    mid = (l + r) >> 1;
                    if (getsum(mid) <t)
                    {
                        l = mid+1;
                    }
                    else
                    {
                        r = mid;
                    }
                }
                if (l == MAX-1)
                {
                    printf("Not Find!\n");
                }
                else
                {
                    printf("%d\n", l);
                }
            }
        }
    }
    return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值