1. 程式人生 > >HDU 4302(zkw線段樹-單點修改區間最值)

HDU 4302(zkw線段樹-單點修改區間最值)

Holedox Eating

Problem Description Holedox在一條長度為L的線上. Holedox能在線上移動,線上會時不時的出現蛋糕(保證是整點)。Holedox會在想吃蛋糕時去最近的有蛋糕的點吃,如果左右的最近蛋糕與它的距離相等,它會按上一次行走的方向,如果沒有蛋糕,它會呆在原地。

Input 第一行為資料組數T (1 <= T <= 10) 對每組資料,第一行有2個整數L,n(1<=L,n<=100000)表示線段長度和事件數。 接下來n行,每行一個事件:‘0 x'表示在x的位置出現一塊蛋糕,’1‘表示Holedox去吃1塊蛋糕
Holedox一開始在0點。
Output 對每組資料,輸出一行‘Case i: dis',dis表示Holedox的移動距離。
Sample Input 3 10 8 0 1 0 5 1 0 2 0 0 1 1 1 10 7 0 1 0 5 1 0 2 0 0 1 1 10 8 0 1 0 1 0 5 1 0 2 0 0 1 1
Sample Output Case 1: 9 Case 2: 4 Case 3: 2

這題是單點修改+區間最值的zkw線段樹(a[]表示數量)

這題有幾個技巧:

1.線段樹多開;

2.'0'點的包含(把所有數字+1,顯然不影響Holedox的移動距離)

3.額外資訊的記錄(為了把這題轉換成線段樹)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
using namespace std;
#define MAXT (10+10)
#define MAXN (100000+10)
#define MAXm (100000+10)
#define INF (2139062143)
int n,m,M,T,now,direction,ans;
int t[2][MAXN*10];  //0->max 1->min
int a[MAXN];
void dec(int x)
{
	a[x]--;
	if (a[x]==0)
	{
		x+=M;
		t[0][x]=0;t[1][x]=INF;
		for (x>>=1;x;x>>=1) 
		{
			t[0][x]=max(t[0][x<<1],t[0][(x<<1)^1]);
			t[1][x]=min(t[1][x<<1],t[1][(x<<1)^1]);
		}
	}	
}
void go_left(int Lans)
{
	ans+=now-Lans;
	now=Lans;direction=-1;
	dec(now);				
}
void go_right(int Rans)
{
	ans+=Rans-now;
	now=Rans;direction=1;
	dec(now);				
}
int main()
{
	freopen("Holding.in","r",stdin);
	scanf("%d",&T);
	for (int k=1;k<=T;k++)
	{
		memset(t[0],0,sizeof(t[0]));ans=0;
		memset(t[1],127,sizeof(t[1]));
		memset(a,0,sizeof(a));now=1;direction=1; //1->right -1->left
		scanf("%d%d",&n,&m);n+=2;
		M=1;while (M-2<n) M<<=1;
		for (int i=1;i<=m;i++)
		{
			int p1,p2;
			scanf("%d",&p1);
			if (p1==0)
			{
				scanf("%d",&p2);p2+=1;
				a[p2]++;
				if (a[p2]==1)
				{
					p2+=M;t[0][p2]=t[1][p2]=p2-M;
					int p=p2;
					for (p>>=1;p;p>>=1) t[0][p]=max(t[0][p<<1],t[0][(p<<1)^1]);
					for (p2>>=1;p2;p2>>=1) t[1][p2]=min(t[1][p2<<1],t[1][(p2<<1)^1]);
				}				
			}
			else
			{
				//(0,now+1)->[1,now]
				int l=M,r=now+1+M,Lans=0,Rans=INF;
				while (l^r^1)
				{
					if (~l&1) Lans=max(Lans,t[0][l+1]);
					if (r&1) Lans=max(Lans,t[0][r-1]);
					l>>=1;r>>=1;
				}
				//(now-1,n)->[now,n-1]
				l=now-1+M;r=n+M;
				while (l^r^1)
				{
					if (~l&1) Rans=min(Rans,t[1][l+1]);
					if (r&1) Rans=min(Rans,t[1][r-1]);
					l>>=1;r>>=1;
				}
				if (Lans==0&&Rans==INF) continue;
				else if (Lans==0) go_right(Rans);
				else if (Rans==INF) go_left(Lans);
				else if (now-Lans<Rans-now) go_left(Lans);
				else if (now-Lans>Rans-now) go_right(Rans);
				else if (now-Lans==0) dec(now);
				else if (direction==1) go_right(Rans);
				else go_left(Lans);
				
				
				
				
			}
			/*
				for (int j=1;j<=M*2;j++) if (t[0][j]) cout<<j<<":"<<t[0][j]<<' ';
				cout<<endl;
				for (int j=1;j<=M*2;j++) if (t[1][j]<INF) cout<<j<<":"<<t[1][j]<<' ';
				cout<<endl;
			*/	
			
			
			
			
		}	
		printf("Case %d: %d\n",k,ans);
		
	}
	return 0;
}