http://www.lydsy.com/JudgeOnline/problem.php?id=3924
抓紧时间补上以前忘写的博客
先考虑如何求出对于一个点,其它所有点到它的带权距离和,显然用树分治结构就可以动态维护,查询复杂度logn。由于时限宽松,可以考虑每次利用分治从头暴力求重心,方法是从根开始判断是否存在一个方向使得移动过去更优,有的话就跳到那层分治结构上。总复杂度n*log^2(n)
#include<cstdio>
#include<algorithm>
#define gm 100001
using namespace std;
const size_t str=1<<16;
typedef long long ll;
struct Reader
{
char buf[str],*s,*t;
Reader():s(),t(),buf(){}
inline char pick()
{
return (s==t)?(t=buf+fread(s=buf,1,str,stdin),*s++):(*s++);
}
Reader& operator >> (int &x)
{
register char c;
register bool negtive=0;
do c=pick(); while((c<'0'||c>'9')&&c!='-');
if(c=='-') negtive=1,c=pick();
x=0;
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=pick();
return x=negtive?-x:x,*this;
}
}cin;
struct Writer
{
char buf[str],*s,*t;
Writer():s(buf),t(buf+str),buf(){}
~Writer(){fwrite(buf,1,s-buf,stdout);}
inline void echo(char c)
{
(s==t)?(fwrite(s=buf,1,str,stdout),*s++=c):(*s++=c);
}
Writer& operator << (ll x)
{
if(!x) return echo('0'),*this;
register char a[21],t=1;
while(x) a[t++]=x%10,x/=10;
while(--t) echo(a[t]+'0');
return *this;
}
Writer& operator << (const char* s)
{
while(*s) echo(*s++);
return *this;
}
}cout;
const char *endl="\n";
struct e
{
int t;
e *n;
int c;
e(int t,e *n,int c):t(t),n(n),c(c){}
}*f[gm],*g[gm];
int n,q;
namespace RMQ
{
int log[gm<<1];
int dep[gm];
int dis[gm];
int pos[gm];
int a[gm<<1][17];
int top=0;
void dfs(int x,int from)
{
a[pos[x]=++top][0]=x;
dep[x]=dep[from]+1;
for(e *i=f[x];i;i=i->n)
{
if(i->t==from) continue;
dis[i->t]=dis[x]+i->c;
dfs(i->t,x);
a[++top][0]=x;
}
}
inline int min(int a,int b)
{
return dep[a]<dep[b]?a:b;
}
void init()
{
dfs(1,0);
for(int i=2;i<=top;++i)
{
log[i]=log[i>>1]+1;
}
for(int i=1;i<=log[top];++i)
{
for(int j=1;j+(1<<i-1)<=top;++j)
{
a[j][i]=min(a[j][i-1],a[j+(1<<i-1)][i-1]);
}
}
}
int LCA(int x,int y)
{
x=pos[x],y=pos[y];
if(y<x) x^=y^=x^=y;
int len=log[y-x+1];
return min(a[x][len],a[y-(1<<len)+1][len]);
}
int distance(int x,int y)
{
return dis[x]+dis[y]-(dis[LCA(x,y)]<<1);
}
}
namespace DAC
{
ll self[gm],tof[gm],sum[gm];
bool ban[gm];
int _sz[gm],sz[gm],fa[gm];
int size(int x,int from)
{
int &res=_sz[x]=1;
for(e *i=f[x];i;i=i->n)
{
if(i->t==from||ban[i->t]) continue;
res+=size(i->t,x);
}
return res;
}
int centre(int x,int from,int lim)
{
for(e *i=f[x];i;i=i->n)
{
if(i->t==from||ban[i->t]) continue;
if(_sz[i->t]>lim>>1) return centre(i->t,x,lim);
}
return x;
}
int solve(int x)
{
int temp=size(x,0);
x=centre(x,0,temp);
sz[x]=temp;
ban[x]=1;
for(e *i=f[x];i;i=i->n)
{
if(ban[i->t]) continue;
int y=solve(i->t);
fa[y]=x;
g[x]=new e(y,g[x],(int)i);
}
return x;
}
int root;
void init()
{
root=solve(1);
}
void cast(int u,int e)
{
sum[u]+=e;
for(int i=u;fa[i];i=fa[i])
{
int j=fa[i];
ll dis=RMQ::distance(u,j);
self[j]+=dis*e;
tof[i]+=dis*e;
sum[j]+=e;
}
}
ll get(int x)
{
ll res=self[x];
for(int i=x;fa[i];i=fa[i])
{
int j=fa[i];
ll path=self[j]-tof[i];
ll val=sum[j]-sum[i];
res+=path+val*RMQ::distance(x,j);
}
return res;
}
ll query(int x=root)
{
ll kre=get(x);
for(e *i=g[x];i;i=i->n)
{
ll sre=get(((e*)(i->c))->t);
if(sre<kre) return query(i->t);
}
return kre;
}
}
int main()
{
cin>>n>>q;
for(int i=1;i<n;++i)
{
int a,b,c;
cin>>a>>b>>c;
f[a]=new e(b,f[a],c);
f[b]=new e(a,f[b],c);
}
RMQ::init();
DAC::init();
for(int i=1;i<=q;++i)
{
int u,e;
cin>>u>>e;
DAC::cast(u,e);
cout<<DAC::query()<<endl;
}
return 0;
}