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
Case 1: 9 Case 2: 4 Case 3: 2
这道题神奇得可以用三种方法,线段树容易想到但难敲,堆相对容易,multiset这种奇淫巧计竟然也可以过:
线段树:
#include<iostream> #include<stdio.h> #include<string.h> #include<queue> #include<cmath> #include<stack> #include<algorithm> using namespace std; const int N=100005; struct node { int l,r; int sum; }mem[N*3]; int num[N];//记录某个位置的食物数量 int place,suml,sumr;//小动物的位置 和它左边 右边的食物数量 int to;//表示方向 1 向右 0 向左 int ans;//保存答案 int L,R;//搜索左边和右边最靠近小动物的食物位置 int Search(int,int ); void insert(int ,int ,int ); void Right()//选择右边的食物 进行的一些必要更新 { to=1; sumr-=num[R]; insert(1,R,-num[R]); --num[R]; ans=ans+R-place; place=R; } void Left()//选择左边的食物 进行的一些必要更新 { to=0; suml-=num[L]; insert(1,L,-num[L]); --num[L]; ans=ans+place-L; place=L; } void build(int x,int i,int j)//建树 { mem[x].l=i; mem[x].r=j; mem[x].sum=0; if(i==j) return ; int mid=(i+j)>>1; build(x*2,i,mid); build(x*2+1,mid+1,j); } void insert(int x,int p,int k)//在p这个位置 插入k个食物 k可以为负 用来减少操作 { int mid=(mem[x].l+mem[x].r)>>1; if(mem[x].l==mem[x].r) { mem[x].sum+=k; return ; } if(p<=mid) insert(x*2,p,k); else insert(x*2+1,p,k); mem[x].sum=mem[x*2].sum+mem[x*2+1].sum; } int Search(int x,int d)//搜索第d个食物的位置 { if(mem[x].l==mem[x].r) return mem[x].r; if(mem[x*2].sum>=d) return Search(x*2,d); else return Search(x*2+1,d-mem[x*2].sum); } int main() { int T; scanf("%d",&T); for(int w=1;w<=T;++w) { int n,m; place=0,suml=0,sumr=0; to=1; ans=0; scanf("%d %d",&n,&m); build(1,0,n); memset(num,0,sizeof(num)); while(m--) { int k,x; scanf("%d",&k); if(k==0) { scanf("%d",&x); ++num[x]; if(x!=place)//插入位置 不是在小动物位置才更新线段树 insert(1,x,1); if(x<place) ++suml; else if(x>place) ++sumr; }else { if(num[place]>0)//在小动物位置 直接减少 不需其他操作 { --num[place]; continue; } if(suml==0&&sumr==0)//没有食物 continue; if(sumr==0)//右边没食物 选左边的 { L=Search(1,suml); Left(); }else if(suml==0)//选右边的 { R=Search(1,1); Right(); }else if(suml>0&&sumr>0) { L=Search(1,suml);//求的左边最近食物位置 R=Search(1,suml+1);//求的右边最近食物位置 if(place-L<R-place||(place-L==R-place&&to==0)) Left(); else Right(); } } } printf("Case %d: %d\n",w,ans); } return 0; }
堆:
#include<iostream> #include<queue> #include<algorithm> using namespace std; priority_queue<int,vector<int>,greater<int> > minQue; priority_queue<int> maxQue; int main(){ long long res; int k,l,n,left,targ,val,right,curr,dir; while(scanf("%d",&k)!=EOF){ for(int i=1;i<=k;i++){ while(!minQue.empty()) minQue.pop(); while(!maxQue.empty()) maxQue.pop(); res=0; curr=0; dir=1; scanf("%d%d",&l,&n); while(n--){ scanf("%d",&targ); if(targ){ if(minQue.empty()){ if(!maxQue.empty()){ left=maxQue.top(); maxQue.pop(); res+=curr-left; if(curr!=left) dir=0; curr=left; } } else{ if(maxQue.empty()){ right=minQue.top(); minQue.pop(); res+=right-curr; curr=right; dir=1; } else{ left=maxQue.top(); right=minQue.top(); if(curr-left<right-curr){ res+=curr-left; if(curr!=left) dir=0; curr=left; maxQue.pop(); } else if(curr-left>right-curr){ res+=right-curr; dir=1; curr=right; minQue.pop(); } else{ if(dir){ res+=right-curr; dir=1; curr=right; minQue.pop(); } else{ res+=curr-left; if(curr!=left) dir=0; curr=left; maxQue.pop(); } } } } } else{ scanf("%d",&val); if(val<=curr) maxQue.push(val); else minQue.push(val); } } printf("Case %d: ",i); cout<<res<<endl; } } return 0; }
multiset:
#include<iostream> #include<cstring> #include<cstdio> #include<set> #include<cmath> using namespace std; int main(){ int t; long long sum; int L,n; int a,b; long long Min,p; scanf("%d",&t); for(int Case=1;Case<=t;Case++){ scanf("%d%d",&L,&n); sum=0; multiset<int>s; //multiset用红黑树来组织元素数据,题目中需要允许重复插入元素键值,故不用set multiset<int>::iterator It,del; int cur=0,pre=0; while(n--){ scanf("%d",&a); if(a==0){ scanf("%d",&b); s.insert(b); } else{ Min=0x3fffffff; if(!s.size()) continue; for(It=s.begin();It!=s.end();It++){ if(abs(*It-cur)<Min){ Min=abs((*It)-cur); p=(*It); //得到距离最近的那个蛋糕的位置 del=It; //标记要吃的蛋糕,以便于删除 } else if(abs(*It-cur)==Min){ //当距离一样时取同方向的 if((*It-cur)*(cur-pre)>0){ Min=abs((*It)-cur); p=(*It); del=It; } } } s.erase(del); sum+=Min; pre=cur; //之前所在的位置 cur=p; //目前的位置 } } printf("Case %d: %I64d\n",Case,sum); } // system("pause"); return 0; }