zoukankan      html  css  js  c++  java
  • BZOJ3672 [Noi2014]购票

    题解:

    首先dp方程很简单 dp[i]=min(dp[j]+p[i]*dist(i,j)+q[i])

    显然是可以斜率优化的

    (dp[j]-dp[k])/(dis[j]-dis[k])<p[i]

    那么我们的目的就是要维护这个凸包

    由于p[i]不具有单调性,所以最优解是要三分的

    然后我们先考虑这个问题在链上

    现在的问题在于,还有li这个限制

    于是我们可以选择建立线段树,对线段树每个区间维护其内的凸包

    这样我们可以在nlog^2 n的时间内完成链上

    考虑回到树上

    我们可以直接树剖 这样是nlog^3 n的

    由于树剖常数很小,所以也可以过啊

     线段树和树剖写的都很顺利。。然后就wa了

    对拍了发现又犯了个智障错误。。 先改了ans再查。。

    不知道为什么还能过那么多

    为了比较简单 我都用了ll。。懒得改int

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define IL inline
    #define rint register ll
    #define rep(i,h,t) for (rint i=h;i<=t;i++)
    #define dep(i,t,h) for (rint i=t;i>=h;i--)
    IL ll max(ll x,ll y)
    {
      if (x>y) return(x); else return(y);
    }
    IL ll min(ll x,ll y)
    {
      if (x<y) return(x); else return(y); 
    }
    IL void swap(ll &x,ll &y)
    {
      ll tmp=x; x=y; y=tmp;
    }
    char ss[1<<27],*A=ss,*B=ss;
    IL char gc()
    {
      return A==B&&(B=(A=ss)+fread(ss,1,1<<27,stdin),A==B)?EOF:*A++;
    }
    template<class T> void read(T &x)
    {
      rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=c^48;
      while (c=gc(),47<c&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
    }
    #define mid ((h+t)/2)
    const ll N=5.3e5;
    const ll INF=1e18;
    ll now[N],p[N],q[N],head[N],size[N],son[N],fa[N],top[N],id[N],real2[N],dep[N],dis[N],dp[N],l[N],lx,num;
    ll bz1[20][N],bz2[20][N],n,m;
    struct re{
      ll a,b,c,d;
    }a[N];
    vector<ll> ve[N*4];
    vector<re> ve1[N];
    IL void arr(ll x,ll y,ll z)
    {
      a[++lx].a=head[x];
      a[lx].b=y;
      a[lx].c=z;
      head[x]=lx;
    }
    void dfs1(ll x,ll y)
    {
      ll u=head[x];
      fa[x]=y; son[x]=-1; size[x]=1; dep[x]=dep[y]+1;
      while(u)
      {
        ll v=a[u].b;
        dis[v]=dis[x]+a[u].c;
        dfs1(v,x);
        bz1[0][v]=x;
        bz2[0][v]=a[u].c;
        size[x]+=size[v];
        if (son[x]==-1||size[v]>size[son[x]]) son[x]=v;
        u=a[u].a;
      }
    }
    void dfs2(ll x,ll y)
    {
      top[x]=y; id[x]=++num; real2[num]=x;
      if (son[x]==-1) return;
      dfs2(son[x],y);
      ll u=head[x];
      while (u)
      {
        ll v=a[u].b;
        if (v!=son[x]) dfs2(v,v);
        u=a[u].a;
      }
    }
    IL double check1(ll x,ll y)
    {
      return(1.00000000*(dp[x]-dp[y])/(dis[x]-dis[y]));
    }
    ll query(ll x,ll h,ll t,ll h1,ll t1,ll k)
    {
      if (h1<=h&&t<=t1)
      {
        if (!now[x]) return(INF);
        ll l=0,r=now[x]-1;
        while (l<r)
        {
          ll midd=(l+r)/2;
          if (check1(ve[x][midd+1],ve[x][midd])<=p[k]) l=midd+1;
          else r=midd;
        }
        ll xx=ve[x][l];
        return(dp[xx]+p[k]*(dis[k]-dis[xx])+q[k]);
      }
      ll ans=INF;
      if (h1<=mid) ans=query(x*2,h,mid,h1,t1,k);
      if (mid<t1) ans=min(ans,query(x*2+1,mid+1,t,h1,t1,k));
      return(ans);
    }
    IL bool check2(ll x,ll y,ll z)
    {
      if (1.00000000*(dp[z]-dp[x])/(dis[z]-dis[x])>=1.0000000*(dp[x]-dp[y])/(dis[x]-dis[y]))
        return(1); else return(0);
    }
    void change(ll x,ll h,ll t,ll pos,ll k)
    {
      ll l=0,r=now[x]-1;
      while (l<r)
      {
        ll midd=(l+r)/2;
        if (check2(ve[x][midd+1],ve[x][midd],k)) l=midd+1;
        else r=midd;
      }
      //ve1[k].push_back((re){x,now[k],l+1,l+1<=now[k]?ve[k][l+1]:-1});
      if (!now[x]) now[x]=1; else now[x]=l+2;
      //if (now[x]>=ve[x].size()) ve[x].push_back(k); else ve[x][l+1]=k;
      if (now[x]>ve[x].size()) ve[x].push_back(k); else ve[x][now[x]-1]=k;
      if (h==t) return;
      if (pos<=mid) change(x*2,h,mid,pos,k);
      else change(x*2+1,mid+1,t,pos,k);
    }
    void dfs3(ll x)
    {
      ll f1=top[x],xy=x;
      ll ans=INF;
      while (x&&dep[l[xy]]<=dep[x])
      {
        if (dep[l[xy]]<=dep[f1]) ans=min(ans,query(1,1,n,id[f1],id[x],xy));
        else ans=min(ans,query(1,1,n,id[l[xy]],id[x],xy));
        x=fa[f1]; f1=top[x];
      }
      x=xy;
      if (x!=1) dp[x]=ans; else dp[x]=0;
      change(1,1,n,id[x],x);
      ll u=head[x];
      while (u)
      {
        ll v=a[u].b;
        dfs3(v);
        u=a[u].a;
      }
    /*  rep(i,0,ve1[x].size())
      {
        re xx=ve1[x][i];
        now[xx.a]=xx.b;
        if (xx.d!=-1)
        {
          ve[xx.a][xx.c]=xx.d;
        }
      } */
    }
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      read(n); read(m);
      rep(i,2,n)
      {
        ll x,y;
        read(x); read(y);
        arr(x,i,y);
        read(p[i]); read(q[i]); read(l[i]);
      }
      dfs1(1,0);
      dfs2(1,1);
      rep(i,1,19)
        rep(j,1,n)
        {
          bz1[i][j]=bz1[i-1][bz1[i-1][j]];
          bz2[i][j]=bz2[i-1][j]+bz2[i-1][bz1[i-1][j]];
        }
      rep(i,1,n)
      {
        ll ans=i;
        dep(j,19,0)
          if (l[i]>=bz2[j][ans]) l[i]-=bz2[j][ans],ans=bz1[j][ans];
        l[i]=max(ans,1);
      }
      dfs3(1);
      rep(i,2,n) printf("%lld
    ",dp[i]);
      return 0; 
    }

    考虑一下理论复杂度更小的办法

    现在我们需要的是一个支持撤销的操作

    由于每次修改,我们只会修改栈顶位置和当前栈顶位置的元素

    这个显然我们是可以通过vector记录来完成的

    这样是nlog^2n的

    然而 事实是 这个跑的比树剖

    我也不是很理解为什么啊。。

    常数应该就是2倍啊

    难道开了o2vector还是那么慢啊??

    树剖的log难道<2?? 

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define IL inline
    #define rint register ll
    #define rep(i,h,t) for (rint i=h;i<=t;i++)
    #define dep(i,t,h) for (rint i=t;i>=h;i--)
    IL ll max(ll x,ll y)
    {
      if (x>y) return(x); else return(y);
    }
    IL ll min(ll x,ll y)
    {
      if (x<y) return(x); else return(y); 
    }
    IL void swap(ll &x,ll &y)
    {
      ll tmp=x; x=y; y=tmp;
    }
    char ss[1<<27],*A=ss,*B=ss;
    IL char gc()
    {
      return A==B&&(B=(A=ss)+fread(ss,1,1<<27,stdin),A==B)?EOF:*A++;
    }
    template<class T> void read(T &x)
    {
      rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=c^48;
      while (c=gc(),47<c&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
    }
    #define mid ((h+t)/2)
    //const ll N=6.3e5;
    const int N2=2.3e5;
    const ll INF=1e18;
    ll now[N2*4],p[N2],q[N2],head[N2];
    ll dep[N2],dis[N2],dp[N2],l[N2],lx,num;
    int bz1[20][N2];
    ll bz2[20][N2],n,m;
    struct re{
      ll a,b,c,d;
    }a[N2];
    vector<ll> ve[N2*4];
    vector<re> ve1[N2];
    IL void arr(ll x,ll y,ll z)
    {
      a[++lx].a=head[x];
      a[lx].b=y;
      a[lx].c=z;
      head[x]=lx;
    }
    void dfs1(ll x,ll y)
    {
      ll u=head[x];
      //fa[x]=y; son[x]=-1; size[x]=1; 
      dep[x]=dep[y]+1;
      while(u)
      {
        ll v=a[u].b;
        dis[v]=dis[x]+a[u].c;
        dfs1(v,x);
        bz1[0][v]=x;
        bz2[0][v]=a[u].c;
        //size[x]+=size[v];
        //if (son[x]==-1||size[v]>size[son[x]]) son[x]=v;
        u=a[u].a;
      }
    }
    /* void dfs2(ll x,ll y)
    {
      top[x]=y; id[x]=++num; real2[num]=x;
      if (son[x]==-1) return;
      dfs2(son[x],y);
      ll u=head[x];
      while (u)
      {
        ll v=a[u].b;
        if (v!=son[x]) dfs2(v,v);
        u=a[u].a;
      }
    } */
    IL double check1(ll x,ll y)
    {
      return(1.00000000*(dp[x]-dp[y])/(dis[x]-dis[y]));
    }
    ll query(ll x,ll h,ll t,ll h1,ll t1,ll k)
    {
      if (h1<=h&&t<=t1)
      {
        if (!now[x]) return(INF);
        ll l=0,r=now[x]-1;
        while (l<r)
        {
          ll midd=(l+r)/2;
          if (check1(ve[x][midd+1],ve[x][midd])<=p[k]) l=midd+1;
          else r=midd;
        }
        ll xx=ve[x][l];
        return(dp[xx]+p[k]*(dis[k]-dis[xx])+q[k]);
      }
      ll ans=INF;
      if (h1<=mid) ans=query(x*2,h,mid,h1,t1,k);
      if (mid<t1) ans=min(ans,query(x*2+1,mid+1,t,h1,t1,k));
      return(ans);
    }
    IL bool check2(ll x,ll y,ll z)
    {
      if (1.00000000*(dp[z]-dp[x])/(dis[z]-dis[x])>=1.0000000*(dp[x]-dp[y])/(dis[x]-dis[y]))
        return(1); else return(0);
    }
    void change(ll x,ll h,ll t,ll pos,ll k)
    {
      ll l=0,r=now[x]-1;
      while (l<r)
      {
        ll midd=(l+r)/2;
        if (check2(ve[x][midd+1],ve[x][midd],k)) l=midd+1;
        else r=midd;
      }
      /*ve1[k].push_back((re){x,now[x],l+1,l+1<now[x]?ve[x][l+1]:-1});
      if (!now[x]) now[x]=1; else now[x]=l+2;
      if (now[x]>ve[x].size()) ve[x].push_back(k); else ve[x][now[x]-1]=k;
      */ int tmp=now[x]; 
      if (!now[x]) now[x]=1; else now[x]=l+2;
      if (now[x]>ve[x].size()) 
        ve[x].push_back(k),ve1[k].push_back((re){x,tmp,-1,-1});
      else ve1[k].push_back((re){x,tmp,now[x]-1,ve[x][now[x]-1]}),ve[x][now[x]-1]=k;
      if (h==t) return;
      if (pos<=mid) change(x*2,h,mid,pos,k);
      else change(x*2+1,mid+1,t,pos,k);
    }
    void dfs3(ll x)
    {
      ll ans=INF;
      /*vector<ll> ve2[N];
      int now2[N];
       for (int i=1;i<=n;i++) 
        for (int j=1;j<=now[i];j++)
          cout<<ve[i][j-1]<<" ";
      cout<<"              "<<x<<"a"<<endl; 
      for (int i=1;i<=n;i++)
        for (int j=1;j<=now[i];j++)
          ve2[i].push_back(ve[i][j-1]),now2[i]=now[i]; */
      ans=query(1,1,n,dep[l[x]],dep[x],x);
      if (x!=1) dp[x]=ans; else dp[x]=0; 
      change(1,1,n,dep[x],x);
      ll u=head[x];
      while (u)
      {
        ll v=a[u].b;
        dfs3(v);
        u=a[u].a;
      }
      rep(i,0,ve1[x].size()-1)
      {
        re xx=ve1[x][i];
        now[xx.a]=xx.b;
        if (xx.d!=-1)
        {
          ve[xx.a][xx.c]=xx.d;
        }
      }
    /*
      for (int i=1;i<=n;i++) 
        for (int j=1;j<=now[i];j++)
          cout<<ve[i][j-1]<<" ";
      cout<<"              "<<x<<endl; */
      
     /* for (int i=1;i<=n;i++) 
        for (int j=1;j<=now[i];j++)
          if (ve[i][j-1]!=ve2[i][j-1]) 
            cout<<now[i]<<" "<<now2[i]<<"false"<<endl;*/
    }
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      read(n); read(m);
      rep(i,2,n)
      {
        ll x,y;
        read(x); read(y);
        arr(x,i,y);
        read(p[i]); read(q[i]); read(l[i]);
      }
      dfs1(1,0);
    //  dfs2(1,1);
      rep(i,1,19)
        rep(j,1,n)
        {
          bz1[i][j]=bz1[i-1][bz1[i-1][j]];
          bz2[i][j]=bz2[i-1][j]+bz2[i-1][bz1[i-1][j]];
        }
      rep(i,1,n)
      {
        ll ans=i;
        dep(j,19,0)
          if (l[i]>=bz2[j][ans]) l[i]-=bz2[j][ans],ans=bz1[j][ans];
        l[i]=max(ans,1);
      }
      dfs3(1);
      rep(i,2,n) printf("%lld
    ",dp[i]);
      return 0; 
    }

    另外一个做法是点分治

    我觉得点分治挺有用的。。

    首先点分治的一个结论是所有联通块的大小之和时nlogn级别的

    然后我们取出重心之后,先做重心和根相连的这一块

    然后对这些点建立凸包,用来更新其他点(点分治和cdq分治线段树分治这些都差不多,也就是利用了离线这一特性)

    我们按照dep[i]-l[i]排序然后依次边建边询问

    这样的复杂度是 nlogn(点数目)*logn(查询时间)

    我记得apio的时候wys说这个有nlogn的做法 但我并不知道。。

  • 相关阅读:
    设计模式_抽象工厂模式
    KMeans聚类算法Hadoop实现
    JDK核心JAVA源代码解析(1)
    pushlet单播与多播
    SQL 2008 R2数据库变为REPLICATION,日志不断增长并且不能截断和收缩的解决方式
    chrome插件的popup与跨域请求
    Ubuntu vim+ ctags(包括系统函数) + taglist 配置
    spring Valid @Pattern 常见的验证表达式
    spring boot 全局异常处理
    spring 事件使用
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/9113290.html
Copyright © 2011-2022 走看看