第 20 题 (树的权值)给定一棵以1为根节点的拥有N个节点的带点权树, 初始时每个点的点权均为0,有Q次操作,每次操作有两种类型:
- 1u,以u为根节点的子树内每个点的点权均加1。
- 2uv,将节点u到节点v的简单路径上的点的点权均加1。
每次操作后询问使 $\sum_{y=1}^{N}A_y \times dist(x,y)$ 最小的x,其中dist(x,y)表示点x到点y的路径上的边数,如果有多个,请输出离根节点1最近的那个。
数据范围:N,Q≤10^5。
提示:显然答案就是求带权重心,直接上轻重链剖分,以线段树上二分求出中位数,每次倍增向上跳,判断是否符合条件即可。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+10;
int n,m, fir[N], nxt[N<<1],son[N<<1],tot;
int dep[N], sz[N],mx[N], dfn[N], top[N],bk[N],cnt,f[N][21];
inline void Add(int x,int y) {
nxt[++tot]=fir[x];
fir[x]=tot;
son[tot]=y;
}
inline void Dfs1 (int x,int fa) {
int i;
f[x][0]=fa;
sz[x]=1;
dep[x]=dep[fa]+1;
for (i=fir[x]; i; i=nxt[i])
if (son[i] !=fa) {
Dfs1 (son[i],x);
sz[x]+=sz[son[i]];
if (__(1)__)
mx[x]=son[i];
}
}
inline void Dfs2(int x,int Top) {
top[x]=Top;
dfn[x]=++cnt;
bk[cnt]=x;
if (mx[x])
Dfs2(mx[x], Top);
int i;
for (i=fir[x]; i; i=nxt[i])
if (son[i]!=f[x][0] && son[i] !=mx[x]) {
Dfs2 (son[i],son[i]);
}
}
LL T[N<<2],tg[N<<2];
inline void pushup(int x) {
T[x]=T[x<<1]+T[x<<1|1];
}
inline void pushdown(int x,int l,int r) {
if (tg[x]) {
int mid=l+r>>1;
T[x<<1]+=tg[x]*(mid-l+1);
T[x<<1|1]+=tg[x]*(r-mid);
tg[x<<1]+=tg[x];
tg[x<<1|1]+=tg[x];
tg[x]=0;
}
}
inline void Modify(int L,int R,int v,int x=1,int l=1,int r=n) {
if (L<=l && r<=R) {
T[x]+=__(2)__;
tg[x]+=v;
return;
}
pushdown(x,l,r);
int mid=l+r>>1;
if (L<=mid)
Modify(L,R,v,x<<1,l,mid) ;
if (R>mid)
Modify(L,R,v,x<<1|1,mid+1,r);
pushup(x);
}
inline LL QuerySum(int L, int R, int x=1,int l=1, int r=n) {
if (L<=1 && r<=R)
return T[x];
LL S=0;
pushdown(x,l,r);
int mid=l+r>>1;
if (L<=mid)
S+=QuerySum(L,R,x<<1,l,mid);
if (R>mid)
S+=QuerySum(L,x<<1|1,mid+1,r);
return S;
}
inline int QueryG(LL k,int x=1,int l=1,int r=n) {
if (l==r)
return __(3)__ ;
pushdown(x,l,r);
int mid=l+r>>1;
if (T[x<<1]>=k)
return QueryG(k,x<<1,l,mid);
else
return QueryG(k-T[x<<1],x<<1|1,mid+1,r);
}
inline void Update(int x,int y) {
while (top[x] !=top[y]) {
if (dep[top[x]]<dep[top[y]])
swap(x,y) ;
Modify (dfn[top[x]],dfn[x],1);
x=f[top[x]][0];
}
if (dfn[x]>dfn[y])
swap(x,y);
Modify(dfn[x],dfn[y],1);
}
inline int Query() {
LL k=T[1]/2+1;
int j,i=bk[QueryG(k)];
if(__(4)__)
return i;
for (j=20; ~j; j--)
if (f[i][j] && __(5)__)
i=f[i][j];
return f[i][0];
}
int main() {
int i,j,o,x,y;
for (cin>>n,i=1; i<n; i++) {
cin>>x>>y;
Add(x,y);
Add(y,x);
}
Dfs1(1,0);
Dfs2(1,1);
for (j=1; j<=20; j++)
for (i=1; i<=n; i++)
f[i][j]=f[f[i][j-1]][j-1];
for (cin>>m; m--;) {
cin>>o>>x;
if (o==1)
Modify (dfn[x], dfn[x]+sz[x]-1,1);
else {
cin>>y;
Update(x,y);
}
cout <<Query()<<endl;
}
return 0;
}