zoukankan      html  css  js  c++  java
  • bzoj 3924 幻想乡战略游戏 —— 动态点分治

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3924

    参考了博客:https://blog.csdn.net/qq_34564984/article/details/53791482

    然后感觉这题其实是很好想的,为了计算答案而维护答案、权值和以及到父亲的答案;

    只要记三个数即可,实现起来也不麻烦;

    查询时可以利用性质(感性理解是对的),枚举原树上的20条出边,哪里更优走哪里;

    为了减少走的次数,每次走到那个出边所在分治块的 rt 即可,这个 rt 一定是原来点在分治树上的一个儿子,因为不会走回父亲(原本就是从父亲走来的,走回去显然不优);

    复杂度算一算应该是 m*20*log2n 的,过不了...?但这题给了 100s 的时限,怎么也过了。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const xn=1e5+5;
    int n,hd[xn],ct,to[xn<<1],nxt[xn<<1],w[xn<<1],tt[xn<<1];
    int siz[xn],dep[xn],fa[xn][20],dis[xn][20],son[xn][25],num[xn],mx,rt;
    ll f[xn],sum[xn],g[xn];
    bool vis[xn];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int Max(int x,int y){return x>y?x:y;}
    int Min(int x,int y){return x<y?x:y;}
    void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct; w[ct]=z;}
    void getrt(int x,int ff,int sum)
    {
      int nmx=0; siz[x]=1;
      for(int i=hd[x],u;i;i=nxt[i])
        {
          if((u=to[i])==ff||vis[u])continue;
          getrt(u,x,sum); siz[x]+=siz[u];
          nmx=Max(nmx,siz[u]);
        }
      nmx=Max(nmx,sum-siz[x]);
      if(nmx<mx)mx=nmx,rt=x;
    }
    void build(int x,int ff,int d)
    {
      for(int i=hd[x],u;i;i=nxt[i])
        {
          if((u=to[i])==ff||vis[u])continue;
          fa[u][++dep[u]]=rt; dis[u][dep[u]]=d+w[i];
          build(u,x,d+w[i]);
        }
    }
    void work(int x,int sum)
    {
      vis[x]=1; build(x,0,0);
      for(int i=hd[x],u;i;i=nxt[i])
        {
          if(vis[u=to[i]])continue;
          int ns=(siz[u]>siz[x]?sum-siz[x]:siz[u]);
          mx=xn; getrt(u,0,ns); tt[i]=rt; work(rt,ns);//tt
        }
    }
    void change(int x,ll v)
    {
      for(int i=dep[x];i;i--)
        {
          int ff=fa[x][i],d=dis[x][i];
          f[ff]+=v*d; sum[ff]+=v; 
          if(i>1)g[ff]+=v*dis[x][i-1];
        }
    }
    ll cal(int x)
    {
      ll ret=0;
      for(int i=dep[x];i;i--)
        {
          int nw=fa[x][i]; ret+=f[nw]; ret-=g[nw];
          if(i>1)ret+=(sum[fa[x][i-1]]-sum[nw])*dis[x][i-1];
        }
      return ret;
    }
    ll query(int x)
    {
      ll val=cal(x);
      //for(int i=1,u;i<=num[x];i++)
      //if(cal(u=son[x][i])<val)return query(u);
      for(int i=hd[x],u;i;i=nxt[i])
        if(cal(u=to[i])<val)return query(tt[i]);
      return val;
    }
    int main()
    {
      n=rd(); int m=rd();
      for(int i=1,x,y,z;i<n;i++)
        x=rd(),y=rd(),z=rd(),add(x,y,z),add(y,x,z);
      mx=xn; getrt(1,0,n); int yrt=rt; work(rt,n);
      //for(int i=1,ff;i<=n;i++)son[ff=fa[i][dep[i]]][++num[ff]]=i;
      for(int i=1;i<=n;i++)fa[i][++dep[i]]=i;
      for(int i=1,x,v;i<=m;i++)
        {
          x=rd(); v=rd(); change(x,v);
          printf("%lld
    ",query(yrt));
        }
      return 0;
    }
  • 相关阅读:
    第十一周编程作业
    第十周作业
    第九周编程作业
    第八周作业总结
    第七周作业编程
    第六周作业总结
    第五周课程总结&试验报告(三)
    第四周课程总结&试验报告(二)
    第三周总结
    java2
  • 原文地址:https://www.cnblogs.com/Zinn/p/10187842.html
Copyright © 2011-2022 走看看