hdu3954線段樹--4

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

 

題意:初始每個英雄的級別爲1,經驗爲0,M li ri ei表示派li--ri去打怪,每個收穫的經驗值爲當前級別level*ei,Q li ri表示查詢li--ri的最大經驗。。。

 

分析:很明顯的線段樹。。。整段更新,整段查詢,但整段更新的時候一段裏面每個更新的值不一定一樣。。大牛說這是中等難度,都不會啊,水。。。

比賽的時候想着對每個節點用個queue保存lazy情況,結果MLE。。。今天又搞了一天啊。。。

後來借鑑了大牛思想。。。http://blog.csdn.net/wsniyufang/article/details/6702560

主要是要利用最大級數不超過10這個條件。。。對每個節點保存這段裏面所有的升級所需的最小的值mn。。。然後更新到這一段時如果ei>=mn,則往下更新,最壞情況下,也只有n*klogn這麼多。。。不會超時。。。
   
還有一種解決方式是對每個結點開一個10的數組,存該節點每一級的最大值。。。。

ps:原來輸入優化也可以優化這麼多的。。。。

 

代碼:

#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;

const int MX=0x7fffffff;
const int N=10010;
int n, k, qw, leve[13], ei;
struct node
{
	int l, r, mid;
	int level, exp, add, mn;
	void init()
	{
		level = 1;
		exp = add = 0;
		mn = leve[2]/1;
	}
} a[N*4];

inline int _max(int a, int b)
{
	return a>b?a:b;
}
inline int _min(int a, int b)
{
	return a<b?a:b;
}
void build(int l, int r, int p)
{
	a[p].l = l;
	a[p].r = r;
	a[p].mid = (l+r)>>1;
	a[p].init();
	if(l==r)
		return;
	build(l, a[p].mid, p*2);
	build(a[p].mid+1, r, p*2+1);
}
//將本層lazy值往下傳。。。
inline void down(int p)
{
	a[p*2].add += a[p].add;
	a[p*2].mn -= a[p].add;
	a[p*2].exp += a[p].add*a[p*2].level;

	a[p*2+1].add += a[p].add;
	a[p*2+1].mn -= a[p].add;
	a[p*2+1].exp += a[p].add*a[p*2+1].level;

	a[p].add = 0;
}
//更新過後用下層的結果更新上層。。
inline void up(int p)
{
	a[p].mn = _min(a[p*2].mn, a[p*2+1].mn);
	a[p].exp = _max(a[p*2].exp, a[p*2+1].exp);
	a[p].level = _max(a[p*2].level, a[p*2+1].level);
}

void update(int l, int r, int p)
{
	if(a[p].l==l && r==a[p].r)
	{
		if(l<r)
		{
			if(ei>=a[p].mn)
			{
				down(p);
				update(l, a[p].mid, p*2);
				update(a[p].mid+1, r, p*2+1);
				up(p);
			}
			else
			{
				a[p].add += ei;
				a[p].exp += ei*a[p].level;
				a[p].mn -= ei;
			}
			return;
		}
		a[p].exp += ei*a[p].level;
		for(int i=a[p].level+1; i<=k && a[p].exp>=leve[i]; i++)
			a[p].level = i;
		a[p].mn = (leve[a[p].level+1]-a[p].exp)/a[p].level+((leve[a[p].level+1]-a[p].exp)%a[p].level!=0);//mn的值表示什麼。。相當關鍵。。
		a[p].add = 0;
		return;
	}

	if(a[p].add!=0)
		down(p);
	if(r<=a[p].mid)
		update(l, r, p*2);
	else if(l>a[p].mid)
		update(l, r, p*2+1);
	else
	{
		update(l, a[p].mid, p*2);
		update(a[p].mid+1, r, p*2+1);
	}
	up(p);
}
int query(int l, int r, int p)
{
	if(a[p].l==l && a[p].r==r)
		return a[p].exp;

	if(a[p].add!=0)
		down(p);
	int ans;
	if(r<=a[p].mid)
		ans = query(l, r, p*2);
	else if(l>a[p].mid)
		ans = query(l, r, p*2+1);
	else
	{
		ans = _max(query(l, a[p].mid, p*2), query(a[p].mid+1, r, p*2+1));
	}
	//up(p); //可以不用。因爲沒有更新,下面不存在會有level變化,上層的值也就不會發生變化。。。
	return ans;
}
//450ms
int main()
{
	int i, cas1, cas, li, ri;
	char op[3];
	//freopen("D.in", "w", stdout);
	scanf("%d", &cas);
	for(cas1=1; cas1<=cas; cas1++)
	{
		scanf("%d%d%d", &n, &k, &qw);
		for(i=2; i<=k; i++)
			scanf("%d", &leve[i]);
		leve[++k] = MX;

		build(1, n, 1);
		printf("Case %d:\n", cas1);
		while(qw--)
		{
			scanf("%s%d%d", op, &li, &ri);
			if(op[0]=='W')
			{
				scanf("%d", &ei);
				update(li, ri, 1);
			}
			else
			{
				printf("%d\n", query(li, ri, 1));
			}
		}
		printf("\n");
	}

	return 0;
}
/*
//輸入優化。。。
//加上這個輸入優化之後居然就可以榜首了。。343MS。。時間差不多少了3/4
inline int nextInt() {    
    char c;    
    while (c = getchar(), c < '0' || c > '9');    
    int r = c - '0';    
    while (c = getchar(), c >= '0' && c <= '9') r = r * 10 + c - '0';    
    return r;    
} 
int main()
{
	int i, j, cas1, cas, li, ri;
	char op[3];
	//freopen("D.in", "w", stdout);
	cas = nextInt();
	for(cas1=1; cas1<=cas; cas1++)
	{
		n=nextInt(); k=nextInt(); qw=nextInt();
		for(i=2; i<=k; i++)
			leve[i] = nextInt();
		leve[++k] = MX;

		build(1, n, 1);
		printf("Case %d:\n", cas1);
		while(qw--)
		{
			scanf("%s", op);
			li = nextInt();
			ri = nextInt();
			if(op[0]=='W')
			{
				//scanf("%d", &ei);
				ei = nextInt();
				update(li, ri, 1);
			}
			else
			{
				printf("%d\n", query(li, ri, 1));
			}
		}
		puts("");
	}
	return 0;
} 
*/


 

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