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\n",query(yrt));
    }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zinn/p/10187842.html