HDU 4302(zkw線段樹-單點修改區間最值)
阿新 • • 發佈:2019-01-25
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; }