線段樹(3) poj2886

題目鏈接:http://poj.org/problem?id=2886

這道題的難點不在於線段樹,而在於反素數和下一個人位置的確定。反素數我準備用一個博客寫。這裏先不講。知道了反素數和下一個人的位置,這道題就轉變爲求第k大數。我記得求第K大數有很多題了, 我的博客就寫了4-5題了。由於存在刪除所以要採用線段樹或樹狀數組。先寫樹狀數組,再寫線段樹,今天又把他們求第k數的思想想了一下。

樹狀數組版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int n, k;
const int MAX = 500000 + 10;
int c[MAX];
struct node
{
	char name[20];
	int card;
}child[MAX];
int a[37]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,
		   7560,10080,15120,20160,25200,27720,45360,50400,  
           55440,83160,110880,166320,221760,277200,332640,498960,500001};  
int b[37]={1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,90,96,
			100,108,120,128,144,160,168,180,192,200,1314521};
			
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 x)
{
	int l = 1, r = n, mid;
	while (l < r)
	{
		mid = (l +r)>>1;
		if (getsum(mid)<x)
		{
			l = mid + 1;
		}
		else
		{
			r = mid;
		}
	}
	return l;  
}
int main()
{
	int i, j;
	while (scanf("%d %d", &n, &k) == 2)
	{
		memset(c, 0, sizeof(c));
		for (i=1; i<=n; i++)
		{
			update(i, 1);
			scanf("%s%d", child[i].name, &child[i].card);
		}
		i=0;
		while (a[i]<=n)
		{
			i++;
		}
		i--;
		int pos = 0, t = n;
		for (j=0; j<a[i]; j++)
		{
			t--;
		
			pos = find(k);
			if (j==a[i]-1)
			{
				break;
			}
			update(pos, -1);
			if (child[pos].card>0)
			{
				k = (k + child[pos].card-1) % t;
				if (k ==0)
				{
					k = t;
				}
			}
			else
			{
				k = ((k + child[pos].card)%t+t) % t;
				if (k == 0)
				{
					k = t;
				}
			}
			
		}
		printf("%s %d\n", child[pos].name, b[i]);
	}
}


線段樹版本:

#include <stdio.h>
#include <string.h>

const int MAX = 500000 + 10;
char name[MAX][11];
int card[MAX];
int c[37]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840,1260,1680,2520,5040,
		   7560,10080,15120,20160,25200,27720,45360,50400,  
           55440,83160,110880,166320,221760,277200,332640,498960,500001};  
int b[37]={1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60,64,72,80,84,90,96,
			100,108,120,128,144,160,168,180,192,200,1314521};
struct node
{
	int l;
	int r;
	int sum;
}a[MAX<<2];

void pushup(int pos)
{
	a[pos].sum = a[pos<<1].sum + a[pos<<1|1].sum;
}

void build(int l, int r, int pos)
{
	a[pos].l = l;
	a[pos].r = r;
	if (l == r)
	{
		a[pos].sum = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, pos<<1);
	build(mid+1, r, pos<<1|1);
	pushup(pos);
}
int query(int key, int pos)
{
	a[pos].sum--;
	if (a[pos].l == a[pos].r)
	{
		return a[pos].r;
	}
	if (key<=a[pos<<1].sum)
	{
		return query(key, pos<<1);
	}
	else
	{
		return query(key - a[pos<<1].sum, pos<<1|1);
	}
}
int main()
{
	int n, k, i, ansscore, anspos, pos;
	while (scanf("%d%d", &n, &k) == 2)
	{
		i = 0;
		while (c[i] <= n)
		{
			i++;
		}
		anspos = c[i-1];
		ansscore = b[i-1];
		build(1, n, 1);
		for (i=1; i<=n; i++)
		{
			scanf("%s%d", name[i], &card[i]);
		}
		for (i=1; i<=anspos; i++)
		{
			n--;
			pos = query(k, 1);
			if (i == anspos)
			{
				break;
			}
			if (card[pos]>0)
			{
				k = (k + card[pos]-1) % n;
				if (k ==0)
				{
					k = n;
				}
			}
			else
			{
				k = (k + card[pos]%n+n) % n;
				if (k == 0)
				{
					k = n;
				}
			}
		}
		printf("%s %d\n", name[pos], ansscore);
	}
}


 

 

發佈了32 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章