zoukankan      html  css  js  c++  java
  • BZOJ3644 : 陶陶的旅行计划

    假设是序列问题,且$S<T$,可以贪心求解,通过维护下述信息进行区间合并。

    对于区间$[l,r]$,维护的信息有:

    $v$:跳到了$geq r$的位置后,可以花费$1$往右最多扩展多少。

    $f[i]$:从$leq l+i$开始跳到$geq r$的位置的最少步数。

    $g[i]$:从$leq l+i$开始跳到$geq r$的位置时,在$f$最小的基础上,可以花费$0$往右最多扩展多少。

    然后树链剖分+线段树维护信息即可。

    时间复杂度$O(amlog^2n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=100005,M=262150,K=20;
    int n,m,i,x,y,a[N],g[N],v[N<<1],nxt[N<<1],ed,f[N],d[N],size[N],son[N],top[N],loc[N],q[N],dfn;char op;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline void merge(int&f,int&g,int x,int y){if(x<f||x==f&&y>g)f=x,g=y;}
    struct P{
      int f[K],g[K],v,len;
      P(){}
      P operator+(const P&b){
        P c;
        for(int i=0;i<K;i++){
          if(i<len){
            if(g[i]>=b.len){
              c.f[i]=f[i];
              c.g[i]=g[i]-b.len;
            }else if(g[i]){
              c.f[i]=f[i]+b.f[g[i]-1];
              c.g[i]=b.g[g[i]-1];
            }else c.f[i]=N;
            if(v>=b.len)merge(c.f[i],c.g[i],f[i]+1,v-b.len);
            else merge(c.f[i],c.g[i],f[i]+b.f[v-1]+1,b.g[v-1]);
          }else{
            if(i-len>=b.len)break;
            c.f[i]=b.f[i-len];
            c.g[i]=b.g[i-len];
          }
        }
        c.v=max(v-b.len,b.v);
        c.len=len+b.len;
        for(int i=1;i<K;i++)if(c.f[i]>c.f[i-1]||c.f[i]==c.f[i-1]&&c.g[i]<c.g[i-1])c.f[i]=c.f[i-1],c.g[i]=c.g[i-1];
        for(int i=c.len;i<K;i++)c.f[i]=N,c.g[i]=0;
        return c;
      }
      void set(int x){
        v=x,len=1;
        f[0]=g[0]=0;
        for(int i=1;i<K;i++)f[i]=N,g[i]=0;
      }
    }vl[M],vr[M],tmp;bool flag;
    inline void up(int x){
      vl[x]=vl[x<<1]+vl[x<<1|1];
      vr[x]=vr[x<<1|1]+vr[x<<1];
    }
    void build(int x,int a,int b){
      if(a==b){
        vl[x].set(q[a]);
        vr[x].set(q[a]);
        return;
      }
      int mid=(a+b)>>1;
      build(x<<1,a,mid),build(x<<1|1,mid+1,b),up(x);
    }
    void change(int x,int a,int b,int c,int d){
      if(a==b){
        vl[x].set(d);
        vr[x].set(d);
        return;
      }
      int mid=(a+b)>>1;
      if(c<=mid)change(x<<1,a,mid,c,d);
      else change(x<<1|1,mid+1,b,c,d);
      up(x);
    }
    void askl(int x,int a,int b,int c,int d){
      if(c<=a&&b<=d){
        if(flag)tmp=tmp+vl[x];else tmp=vl[x],flag=1;
        return;
      }
      int mid=(a+b)>>1;
      if(c<=mid)askl(x<<1,a,mid,c,d);
      if(d>mid)askl(x<<1|1,mid+1,b,c,d);
    }
    void askr(int x,int a,int b,int c,int d){
      if(c<=a&&b<=d){
        if(flag)tmp=tmp+vr[x];else tmp=vr[x],flag=1;
        return;
      }
      int mid=(a+b)>>1;
      if(d>mid)askr(x<<1|1,mid+1,b,c,d);
      if(c<=mid)askr(x<<1,a,mid,c,d);
    }
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    void dfs(int x){
      size[x]=1;d[x]=d[f[x]]+1;
      for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
        f[v[i]]=x,dfs(v[i]);
        size[x]+=size[v[i]];
        if(size[v[i]]>size[son[x]])son[x]=v[i];
      }
    }
    void dfs2(int x,int y){
      q[loc[x]=++dfn]=a[x];top[x]=y;
      if(son[x])dfs2(son[x],y);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]&&v[i]!=son[x])dfs2(v[i],v[i]);
    }
    inline int lca(int x,int y){
      for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
      return d[x]<d[y]?x:y;
    }
    int cnt,pool[1000][2];
    inline int query(int x,int y){
      int z=lca(x,y);
      flag=cnt=0;
      while(top[x]!=top[z]){
        askr(1,1,n,loc[top[x]],loc[x]);
        x=f[top[x]];
      }
      askr(1,1,n,loc[z],loc[x]);
      while(top[y]!=top[z]){
        pool[++cnt][0]=loc[top[y]];
        pool[cnt][1]=loc[y];
        y=f[top[y]];
      }
      if(y!=z){
        pool[++cnt][0]=loc[z]+1;
        pool[cnt][1]=loc[y];
      }
      for(int i=cnt;i;i--)askl(1,1,n,pool[i][0],pool[i][1]);
      return tmp.f[0];
    }
    int main(){
      read(n);
      for(i=1;i<=n;i++)read(a[i]);
      for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
      dfs(1);
      dfs2(1,1);
      build(1,1,n);
      read(m);
      while(m--){
        while((op=getchar())!='Q'&&op!='C');
        read(x),read(y);
        if(op=='C')change(1,1,n,loc[x],y);
        else printf("%d
    ",query(x,y));
      }
      return 0;
    }
    

      

  • 相关阅读:
    蓝翔杯子校内赛练习代码
    [蓝桥杯][算法训练VIP]猴子分苹果
    系统设计部分代码
    坐标离散化
    蒟蒻吃药计划-治疗系列 #round 1 机器分配+挖地雷
    蒟蒻吃药计划
    F小蒟蒻教你卡常
    最长不下降子序列
    最大子段和(DP)
    luogu P1216 (USACO1.5) Number Triangles
  • 原文地址:https://www.cnblogs.com/clrs97/p/8462808.html
Copyright © 2011-2022 走看看