zoukankan      html  css  js  c++  java
  • BZOJ4249 : Walls 防壁

    首先可以将攻击位置整理成折线,答案不变。

    对于一个长度为$k$的询问,若折线不超过两段,那么显然可以暴力贪心求解。

    否则考虑折线中最短的一段$x ightarrow y$,若其长度$leq k$:

    $1.$若$x$是第一个点,那么删除$x$后答案不变。

    $2.$若$y$是最后一个点,那么删除$y$后答案不变。

    $3.$否则$x ightarrow y$位于折线中间,删除$x$和$y$后答案不变。

    如此重复处理之后,每一段长度均$>k$,这说明经过第一段折线后当前询问区间必然位于折线之中,故答案为折线长度减去区间长度。

    将询问按长度从小到大考虑,用链表维护折线,用堆维护最短的折线即可。

    时间复杂度$O(nlog 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++='
    ';
      fwrite(Out,1,ou-Out,stdout);
      return 0;
    }
    

      

  • 相关阅读:
    22. Generate Parentheses
    21. Merge Two Sorted Lists
    20. Valid Parentheses
    19. Remove Nth Node From End of List
    18. 4Sum
    JDK7新特性
    类Enum
    装饰设计模式
    模板设计模式
    反射
  • 原文地址:https://www.cnblogs.com/clrs97/p/7664826.html
Copyright © 2011-2022 走看看