bzoj3924 [Zjoi2015]幻想乡战略游戏
动态点分治的题好恶心啊
思路倒是比较简单,点分树上每个节点维护子树到他的权值和,到他父亲的权值和,以及点权和。
发现查询的是带权重心,于是每次查到一个点,就在他原树的儿子中找一个比他优的,走到那边的点分树上的儿子,没有比他优的话答案就是他。
一开始一直以为知道父亲的答案,儿子的答案可以$log$转移,后来发现不行,但是那样复杂度就变成了$O(nlg^3n)$,卡不过去,所以树上查询距离的话必须要欧拉序O(1)查询。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 #define N 100500 8 #define int long long 9 using namespace std; 10 int val[N]; 11 int e=1,head[N]; 12 struct edge{ 13 int v,w,next; 14 }ed[N<<1]; 15 void add(int u,int v,int w){ 16 ed[e].v=v;ed[e].w=w; 17 ed[e].next=head[u]; 18 head[u]=e++; 19 } 20 int a[2*N],L[N],R[N],cnt,minn[2*N][20],lg[2*N]; 21 void dfs(int x,int fa){ 22 a[++cnt]=val[x];L[x]=cnt; 23 for(int i=head[x];i;i=ed[i].next){ 24 int v=ed[i].v; 25 if(v==fa)continue; 26 val[v]=val[x]+ed[i].w; 27 dfs(v,x);a[++cnt]=val[x]; 28 } 29 if(a[cnt]!=val[x])a[++cnt]=val[x]; 30 R[x]=cnt; 31 } 32 int dis(int x,int y){ 33 int l=R[x],r=L[y]; 34 if(l>r)swap(l,r); 35 return val[x]+val[y]-2*min(minn[l][lg[r-l+1]],minn[r-(1<<lg[r-l+1])+1][lg[r-l+1]]); 36 } 37 int size[N],maxn[N]; 38 bool vis[N]; 39 int root,sum,rt,n,m,tot; 40 int f[N]; 41 vector<pair<int,int> >son[N]; 42 void getroot(int x,int fa){ 43 size[x]=1;maxn[x]=0; 44 for(int i=head[x];i;i=ed[i].next){ 45 int v=ed[i].v; 46 if(v==fa||vis[v])continue; 47 getroot(v,x); 48 size[x]+=size[v]; 49 maxn[x]=max(maxn[x],size[v]); 50 } 51 maxn[x]=max(maxn[x],sum-size[x]); 52 if(maxn[x]<maxn[root])root=x; 53 } 54 void init(int x){ 55 vis[x]=1;int all=sum; 56 for(int i=head[x];i;i=ed[i].next){ 57 int v=ed[i].v; 58 if(vis[v])continue; 59 root=0;sum=size[v]<size[x]?size[v]:all-size[x]; 60 getroot(v,0); 61 son[x].push_back(make_pair(v,root)); 62 f[root]=x; 63 init(root); 64 } 65 } 66 int sum1[N],sum2[N],num[N]; 67 void update(int x,int y){ 68 tot+=y; 69 int now=x; 70 while(now){ 71 num[now]+=y; 72 sum1[now]+=y*dis(x,now); 73 if(f[now])sum2[now]+=y*dis(x,f[now]); 74 now=f[now]; 75 } 76 } 77 int query(int x){ 78 int ans=sum1[x],now=x; 79 while(1){ 80 ans+=(sum1[f[now]]-sum2[now])+(num[f[now]]-num[now])*dis(x,f[now]); 81 now=f[now];if(!f[now])break; 82 } 83 return ans; 84 } 85 int query(){ 86 int now=rt,last,val=sum1[rt]; 87 while(1){ 88 last=now; 89 for(int i=0;i<son[now].size();i++){ 90 int v=son[now][i].first,nxt=son[now][i].second; 91 int w=query(v); 92 if(w<val){now=nxt;val=query(now);break;} 93 } 94 if(now==last)return val; 95 } 96 } 97 void rmq(){ 98 for(int i=1,j=1,tim=0;(i>>1)<=cnt;i<<=1,tim++) 99 while(j<=cnt&&j<(i<<1))lg[j++]=tim; 100 for(int i=1;i<=cnt;i++)minn[i][0]=a[i]; 101 for(int i=1;(1<<i)<=cnt;i++) 102 for(int j=1;j+(1<<i)-1<=cnt;j++) 103 minn[j][i]=min(minn[j][i-1],minn[j+(1<<i-1)][i-1]); 104 } 105 signed main(){ 106 scanf("%lld%lld",&n,&m); 107 for(int i=1,u,v,w;i<n;i++){ 108 scanf("%lld%lld%lld",&u,&v,&w); 109 add(u,v,w);add(v,u,w); 110 } 111 dfs(1,1);rmq(); 112 root=0;maxn[0]=N;sum=n; 113 getroot(1,0); 114 rt=root; 115 init(root); 116 int x,y; 117 while(m--){ 118 scanf("%lld%lld",&x,&y); 119 update(x,y); 120 printf("%lld\n",query()); 121 } 122 return 0; 123 }
人生如梦亦如幻 朝如晨露暮如霞。