题目大意:给定一棵树,每个点有一个点权,多次改变某个点的点权,多次查询带权重心到所有点的带权距离之和
此生无悔入东方,来世愿生幻想乡
首先我们考虑如何计算一个点到所有点的带权距离之和且支持修改
用动态树分治就好了嘛。。。
每个点记录子树中带权距离之和,以及权值之和,再在每个子树中记录一个需要减掉的版本
然后一直向上扫到根就能统计了
↑这段话面对会写动态树分治的人,不会的先去切捉迷藏吧
然后就好搞了。。。
对于分治结构的每一个点,我们枚举它的出边
如果某条出边连向的点的距离之和小于当前点,那么答案一定在那条出边指向的子树中,分治做下去就行了
如果不存在小于当前点的出边,那么当前点就是重心
注意区分【出边指向的点】和【分治子节点】的区别= =
时间复杂度O(nlog^2n*20)
求两点间距离要用RMQLCA否则复杂度多个log BZ上过不去
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n,m;
namespace Tree{
struct abcd{
int to,f,next;
bool ban;
}table[M<<1];
int head[M],tot=1;
int fa[M],dpt[M],dis[M];
int log_2[M<<1],pos[M],a[M<<1][20];
void Add(int x,int y,int z)
{
table[++tot].to=y;
table[tot].f=z;
table[tot].next=head[x];
head[x]=tot;
}
void DFS(int x)
{
static int T=0;
int i;
dpt[x]=dpt[fa[x]]+1;
a[pos[x]=++T][0]=dis[x];
for(i=head[x];i;i=table[i].next)
if(table[i].to!=fa[x])
{
fa[table[i].to]=x;
dis[table[i].to]=dis[x]+table[i].f;
DFS(table[i].to);
a[++T][0]=dis[x];
}
}
void Build_LCA()
{
int i,j;
for(i=2;i<=n-1<<1;i++)
log_2[i]=log_2[i>>1]+1;
for(j=1;j<=log_2[n-1<<1];j++)
for(i=1;i+(1<<j)-1<=n-1<<1;i++)
a[i][j]=min(a[i][j-1],a[i+(1<<j-1)][j-1]);
}
int LCA_Distance(int x,int y)
{
x=pos[x];y=pos[y];
if(x>y) swap(x,y);
int l=log_2[y-x+1];
return min(a[x][l],a[y-(1<<l)+1][l]);
}
int Distance(int x,int y)
{
return dis[x]+dis[y]-2*LCA_Distance(x,y);
}
}
namespace Dynamic_TDC{
struct abcd{
int to,first,next;
}_table[M];
int _head[M],_tot;
int root,fa[M];
long long dis_sum1[M],dis_sum2[M],sum1[M],sum2[M];
void Add(int x,int y,int z)
{
_table[++_tot].to=y;
_table[_tot].first=z;
_table[_tot].next=_head[x];
_head[x]=_tot;
}
int Get_Size(int x,int from)
{
int i,size=1;
for(i=Tree::head[x];i;i=Tree::table[i].next)
{
if(Tree::table[i].ban)
continue;
if(Tree::table[i].to==from)
continue;
size+=Get_Size(Tree::table[i].to,x);
}
return size;
}
int Get_Centre_Of_Gravity(int x,int from,int size,int &cg)
{
int i,re=1,flag=1;
for(i=Tree::head[x];i;i=Tree::table[i].next)
{
if(Tree::table[i].ban)
continue;
if(Tree::table[i].to==from)
continue;
int temp=Get_Centre_Of_Gravity(Tree::table[i].to,x,size,cg);
if(temp<<1>size)
flag=0;
re+=temp;
}
if(size-re<<1>size)
flag=0;
if(flag)
cg=x;
return re;
}
int Tree_Divide_And_Conquer(int x)
{
int i,size=Get_Size(x,0);
Get_Centre_Of_Gravity(x,0,size,x);
for(i=Tree::head[x];i;i=Tree::table[i].next)
{
if(Tree::table[i].ban)
continue;
Tree::table[i].ban=true;
Tree::table[i^1].ban=true;
int temp=Tree_Divide_And_Conquer(Tree::table[i].to);
fa[temp]=x;
Add(x,temp,Tree::table[i].to);
}
return x;
}
void Modify(int x,int delta)
{
int i;
sum1[x]+=delta;
for(i=x;fa[i];i=fa[i])
{
int dis=Tree::Distance(x,fa[i]);
dis_sum1[fa[i]]+=(long long)dis*delta;
dis_sum2[i]+=(long long)dis*delta;
sum1[fa[i]]+=delta;
sum2[i]+=delta;
}
}
long long Calculate(int x)
{
int i;
long long re=dis_sum1[x];
for(i=x;fa[i];i=fa[i])
{
int dis=Tree::Distance(x,fa[i]);
re+=dis_sum1[fa[i]]-dis_sum2[i];
re+=(sum1[fa[i]]-sum2[i])*dis;
}
return re;
}
long long Query(int x)
{
int i;
long long cost=Calculate(x);
for(i=_head[x];i;i=_table[i].next)
{
long long temp=Calculate(_table[i].first);
if(temp<cost)
return Query(_table[i].to);
}
return cost;
}
}
namespace IStream{
#define L (1<<16)
char Get_Char()
{
static char buffer[L],*S,*T;
if(S==T)
{
T=(S=buffer)+fread(buffer,1,L,stdin);
if(S==T) return EOF;
}
return *S++;
}
int Get_Int()
{
bool flag=false;
char c;
int re=0;
do c=Get_Char(); while((c<'0'||c>'9')&&c!='-');
if(c=='-')
flag=true,c=Get_Char();
while(c>='0'&&c<='9')
re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();
return flag?-re:re;
}
}
struct OStream{
char buffer[L],*S;
OStream()
{
S=buffer;
}
void Put_Char(char c)
{
*S++=c;
if(S==buffer+L)
fwrite(buffer,1,L,stdout),S=buffer;
}
void Put_Long_Long(long long x)
{
static int stack[20],top;
if(!x) stack[++top]='0';
while(x)
stack[++top]=x%10+'0',x/=10;
while(top)
Put_Char(stack[top--]);
Put_Char('\n');
}
~OStream()
{
fwrite(buffer,1,S-buffer,stdout);
}
}os;
int main()
{
using namespace IStream;
int i,x,y,z;
cin>>n>>m;
for(i=1;i<n;i++)
{
x=Get_Int();
y=Get_Int();
z=Get_Int();
Tree::Add(x,y,z);
Tree::Add(y,x,z);
}
Tree::DFS(1);
Tree::Build_LCA();
Dynamic_TDC::root=Dynamic_TDC::Tree_Divide_And_Conquer(1);
for(i=1;i<=m;i++)
{
x=Get_Int();y=Get_Int();
Dynamic_TDC::Modify(x,y);
long long temp=Dynamic_TDC::Query(Dynamic_TDC::root);
os.Put_Long_Long(temp);
}
return 0;
}