BZOJ4249 : Walls 防壁
首先可以将攻击位置整理成折线,答案不变。
对于一个长度为$k$的询问,若折线不超过两段,那么显然可以暴力贪心求解。
否则考虑折线中最短的一段$x\rightarrow y$,若其长度$\leq k$:
$1.$若$x$是第一个点,那么删除$x$后答案不变。
$2.$若$y$是最后一个点,那么删除$y$后答案不变。
$3.$否则$x\rightarrow y$位于折线中间,删除$x$和$y$后答案不变。
如此重复处理之后,每一段长度均$>k$,这说明经过第一段折线后当前询问区间必然位于折线之中,故答案为折线长度减去区间长度。
将询问按长度从小到大考虑,用链表维护折线,用堆维护最短的折线即可。
时间复杂度$O(n\log n)$。
#include<cstdio> #include<algorithm> #include<queue> #include<vector> using namespace std; typedef pair<int,int>P; typedef long long ll; const int N=200010,BUF=10000000,OUT=5000000; char Buf[BUF],*buf=Buf,Out[OUT],*ou=Out;int Outn[30],Outcnt; int n,_,m,i,x,b[N],pre[N],nxt[N],cnt,st;bool del[N];ll ans[N],sum; priority_queue<P,vector<P>,greater<P> >q; struct E{int x,y,p;}a[N]; inline bool cmp(const E&a,const E&b){return a.y-a.x<b.y-b.x;} inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;} inline void write(ll x){ if(!x)*ou++=48; else{ for(Outcnt=0;x;x/=10)Outn[++Outcnt]=x%10+48; while(Outcnt)*ou++=Outn[Outcnt--]; } } inline ll ask(int x,int y){ ll ret=sum,c=cnt,k; for(int i=0,o=st;i<2&&o;o=nxt[o],i++){ if(pre[o])ret-=abs(b[o]-b[pre[o]]),c--; if(y<b[o]){ k=b[o]-y; ret+=k; x+=k,y+=k; } if(x>b[o]){ k=x-b[o]; ret+=k; x-=k,y-=k; } } return ret-c*(y-x); } inline void adjust(int lim){ while(!q.empty()&&cnt>=2){ P t=q.top(); if(t.first>lim)return; q.pop(); int x=t.second; if(del[x]||x==st)continue; int y=pre[x]; if(abs(b[x]-b[y])!=t.first)continue; if(y==st){ del[y]=1; pre[st=x]=0; cnt--; sum-=abs(b[x]-b[y]); continue; } if(!nxt[x]){ del[x]=1; nxt[y]=0; cnt--; sum-=abs(b[x]-b[y]); continue; } int A=pre[y],B=nxt[x]; cnt-=2; sum-=abs(b[A]-b[y]); sum-=abs(b[x]-b[y]); sum-=abs(b[x]-b[B]); sum+=abs(b[A]-b[B]); nxt[A]=B,pre[B]=A; del[x]=del[y]=1; q.push(P(abs(b[A]-b[B]),B)); } } int main(){ fread(Buf,1,BUF,stdin);read(n),read(_); for(i=1;i<=n;i++)read(a[i].x),read(a[i].y),a[i].p=i; while(_--){ read(x); if(!m){b[++m]=x;continue;} if(x==b[m])continue; if(m>1&&(x<b[m])==(b[m]<b[m-1]))b[m]=x;else b[++m]=x; } for(st=i=1;i<=m;i++){ if(i>1)pre[i]=i-1; if(i<m)nxt[i]=i+1; if(i>1){ q.push(P(abs(b[i]-b[i-1]),i)); cnt++; sum+=abs(b[i]-b[i-1]); } } sort(a+1,a+n+1,cmp); for(i=1;i<=n;i++)adjust(a[i].y-a[i].x),ans[a[i].p]=ask(a[i].x,a[i].y); for(i=1;i<=n;i++)write(ans[i]),*ou++='\n'; fwrite(Out,1,ou-Out,stdout); return 0; }