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; }