1. 程式人生 > >bzoj 3924 幻想鄉戰略遊戲 —— 動態點分治

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*log2

n 的,過不了...?但這題給了 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; }