链接
点分树裸题!!!
其实是不想写题解
大概就是要新建立点分树,基本上是一个新树了。要维护以每个结点为根的子树信息来辅助查询。
查询的时候就是找子树中比当前结点优的点然后。这里跳到那个结点的根结点去。
还有就是会被菊花卡成O(n)的查询,但是这题有限制子树不超过20个。
#include//注意距离都要开LL
using namespace std;
typedef long long LL;
const int maxn=1e5+105,oo=16;
int np,first[maxn];
struct edge{
int to,next,w;
}E[maxn<<1];
void add(int u,int v,int w)
{
E[++np]=(edge){v,first[u],w};
first[u]=np;
}
int n,m,rt,root;
int dep[maxn],fa[maxn][oo+5],sz[maxn],dist[maxn];
void DFS(int i,int f,int d,int dis)
{
dep[i]=d,dist[i]=dis;
fa[i][0]=f;
for(int j=1;j<=oo;j++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(j==f)continue;
DFS(j,i,d+1,dis+E[p].w);
}
}
int LCA(int u,int v)
{
if(dep[u]int delt=dep[u]-dep[v];
for(int j=oo;j>=0;j--)
if(delt&(1<if(u==v)return u;
for(int j=oo;j>=0;j--)
if(fa[u][j]!=fa[v][j])u=fa[u][j],v=fa[v][j];
return fa[u][0];
}
int getDist(int u,int v)
{
return dist[u]+dist[v]-2*dist[LCA(u,v)];
}
int pa[maxn],sum[maxn];
LL cost[maxn],pacost[maxn];
bool vis[maxn];
int np2,first2[maxn];
struct edge2{
int to,next,rt;
}E2[maxn];
void add2(int u,int v,int rt)
{
E2[++np2]=(edge2){v,first2[u],rt};
first2[u]=np2;
}
void getRoot(int i,int f,int tot)
{
sz[i]=1;
int mx=0;
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(j==f || vis[j])continue;
getRoot(j,i,tot);
mx=max(mx,sz[j]);
sz[i]+=sz[j];
}
mx=max(mx,tot-sz[i]);
if(mx<=tot/2)root=i;
}
void Build(int i,int f,int tot)
{
pa[i]=f;vis[i]=1;
for(int p=first[i];p;p=E[p].next)
{
int j=E[p].to;
if(vis[j])continue;
getRoot(j,0,sz[j]void modify(int u,int e)
{
int dist;
sum[u]+=e;
for(int i=u;pa[i];i=pa[i])
{
dist=getDist(u,pa[i]);
sum[pa[i]]+=e;
cost[pa[i]]+=1ll*dist*e;
pacost[i]+=1ll*dist*e;
}
}
LL calc(int u)
{
int dist;
LL ret=cost[u];
for(int i=u;pa[i];i=pa[i])
{
dist=getDist(u,pa[i]);
ret+=cost[pa[i]]-pacost[i];
ret+=1ll*(sum[pa[i]]-sum[i])*dist;
}
return ret;
}
LL query(int i)
{
LL tmp=calc(i);
for(int p=first2[i];p;p=E2[p].next)
{
int j=E2[p].to;
if(calc(j)return query(E2[p].rt);
}
return tmp;
}
void Init()
{
int u,v,w;
scanf("%d%d",&n,&m);
for(int i=1;iscanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
DFS(1,0,1,0);//因为我们是求个距离,所以随便哪个是根都可以
getRoot(1,0,n);
rt=root;
Build(rt,0,n);
}
int main()
{
//freopen("in.txt","r",stdin);
Init();
int u,e;
while(m--)
{
scanf("%d%d",&u,&e);
modify(u,e);
printf("%lld\n",query(rt));
}
return 0;
}