题意
有一根长为L的管道和一个初始位置在最左端的动物,输入数据"0 x"表示此时在管道的左数x位置出现了一个食物,"1"表示动物想吃东西了:他会吃最近的食物,如果有多个最近的食物,就按照最近一次的移动方法移动,求所有命令结束后的动物移动路程。
思路
这个题目就是要迅速的找到比当前位置大的最小的那个数,和比当前位置小的最大的那个数(或者当前值本身),下面两个方法都是从这个思想入手的。
思路1:构造两个优先队列left和right.left是最大堆,堆顶即为在蛇左边离蛇最近的那块蛋糕;right为最小堆,堆顶为在蛇右边离蛇最近的那块蛋糕.模拟所有情况即可
思路2:线段树,存取每个位置上食物个数,并存区间最大值和最小值,对于一点,若没有食物,那么最大值为-1,最小值为INF,然后就是裸的线段树了.
附代码:
优先队列:
#include<iostream>
#include<queue>
#include<algorithm>
#include<functional>
#include<cstdio>
using namespace std;
priority_queue<int,vector<int>,greater<int> >Right;
priority_queue<int>Left;
int main(){
int T;
int cas=1;
cin>>T;
while(T--){
while(!Left.empty())
Left.pop();
while(!Right.empty())
Right.pop();
int len,n;
cin>>len>>n;
int pos=0;//蛇当前位置
int dir=1;//上次移动的方向
int dis=0;//移动总距离
for(int i=0;i<n;i++){
int a,b;
cin>>a;
if(a==0){
cin>>b;
if(b<=pos)
Left.push(b);
else
Right.push(b);
}
if(a==1){
if(!Left.empty()&&!Right.empty()){
int pos1=Left.top();
int pos2=Right.top();
if(pos-pos1==pos2-pos){
if(dir==0){
Left.pop();
dis+=pos-pos1;
pos=pos1;
}
if(dir==1){
Right.pop();
dis+=pos-pos1;
pos=pos2;
}
}
else if(pos-pos1<pos2-pos){
Left.pop();
dis+=pos-pos1;
pos=pos1;
dir=0;
}
else if(pos-pos1>pos2-pos){
Right.pop();
dis+=pos2-pos;
pos=pos2;
dir=1;
}
}
else if(!Left.empty()){
int pos1=Left.top();
Left.pop();
if(pos!=pos1){
dis+=pos-pos1;
dir=0;
pos=pos1;
}
}
else if(!Right.empty()){
int pos1=Right.top();
Right.pop();
dis+=pos1-pos;
dir=1;
pos=pos1;
}
}
}
printf("Case %d: %d\n",cas++,dis);
}
return 0;
}
线段树:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN=100000+100;
const int INF=0x3fffffff;
struct node
{
int l,r,t,mx,mi;
}seg[MAXN*4];
void build(int i,int l,int r)
{
seg[i].l=l,seg[i].r=r,seg[i].t=0;
seg[i].mx=-1,seg[i].mi=INF;
if(l==r)
return;
int m=(l+r)>>1;
build(i*2,l,m),build(i*2+1,m+1,r);
}
void push_up(int i)
{
if(seg[i].l==seg[i].r) return;
seg[i].mx=max(seg[i*2].mx,seg[i*2+1].mx);
seg[i].mi=min(seg[i*2].mi,seg[i*2+1].mi);
}
void add(int i,int p)
{
if(seg[i].l==seg[i].r)
{
seg[i].t++;
seg[i].mx=seg[i].mi=p;
return;
}
int m=(seg[i].l+seg[i].r)>>1;
if(p<=m) add(i*2,p);
else add(i*2+1,p);
push_up(i);
}
void del(int i,int p)
{
if(seg[i].l==seg[i].r)
{
seg[i].t--;
if(!seg[i].t)
{
seg[i].mx=-1;
seg[i].mi=INF;
}
return;
}
int m=(seg[i].l+seg[i].r)>>1;
if(p<=m) del(i*2,p);
else del(i*2+1,p);
push_up(i);
}
int query1(int i,int l,int r)
{
if(seg[i].l==l&&seg[i].r==r)
return seg[i].mx;
int m=(seg[i].l+seg[i].r)>>1;
if(r<=m) return query1(i*2,l,r);
else if(l>m) return query1(i*2+1,l,r);
else return max(query1(i*2,l,m),query1(i*2+1,m+1,r));
}
int query2(int i,int l,int r)
{
if(seg[i].l==l&&seg[i].r==r)
return seg[i].mi;
int m=(seg[i].l+seg[i].r)>>1;
if(r<=m) return query2(i*2,l,r);
else if(l>m) return query2(i*2+1,l,r);
else return min(query2(i*2,l,m),query2(i*2+1,m+1,r));
}
int main()
{
int cas;
scanf("%d",&cas);
for(int k=1;k<=cas;k++)
{
int n,m;
scanf("%d%d",&n,&m);
build(1,0,n);
int x=0,dir=1,ans=0;
while(m--)
{
int op;
scanf("%d",&op);
if(op==0)
{
int p;
scanf("%d",&p);
add(1,p);
}
else
{
int t1=query1(1,0,x),t2=query2(1,x,n);
if(t1!=-1&&t2!=INF)
{
if(x-t1<t2-x)
{
dir=-1;
del(1,t1);
ans+=x-t1;
x=t1;
}
else if(x-t1>t2-x)
{
dir=1;
del(1,t2);
ans+=t2-x;
x=t2;
}
else
{
if(dir==1)
{
del(1,t2);
ans+=t2-x;
x=t2;
}
else
{
del(1,t1);
ans+=x-t1;
x=t1;
}
}
}
else if(t1!=-1&&t2==INF)
{
del(1,t1);
ans+=x-t1;
x=t1;
dir=-1;
}
else if(t2!=INF&&t1==-1)
{
del(1,t2);
ans+=t2-x;
x=t2;
dir=1;
}
}
}
printf("Case %d: %d\n",k,ans);
}
return 0;
}