洛谷P3925 aaabx 题解
题意分析
给你一颗树,每个点有个权值 \(v_i\),对于每个点,把它子树从小到大排序乘以排名称为这个点的贡献,求每个点的贡献和对 \(10^9+7\) 取余。
题解
下面 \(sz_i\) 就是 \(i\) 的子树大小,\(fa_i\) 为它自己和它所有父亲节点的集合。
先想暴力,暴力就是把每个点子树的权值全部拿出来然后排序,按照上面题意排个序求个贡献在求个和就完了。
但是这样感觉没法优化,于是我们考虑每个点对这个子树的贡献,考虑一些特殊的点,比如说最大的点,最大的点 \(i\) 在它的子树及它所有上级的子树中的贡献就是 \(v_i \times \sum\limits_{j\in fa_i} sz_j\)。
然后我们再考虑次大值,次大值在有刚刚有最大值的子树 \(i\) 中所成排名就会变成 \(sz_i-1\),这样下去我们就得到了一个规律,就是每次处理当前最大值时就把它自己和它所有父亲的 \(sz\) 减一,让后每次都这么做就成了两个操作:
-
求当前点到父亲的 \(sz\) 和。
-
将当前点到父亲的 \(sz\) 减一。
这样就成了一个树链剖分的板子,最终时间复杂度 \(o(n\log^2 n)\)。
代码
#include <bits/stdc++.h>
#define ll long long
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define mkp make_pair
#define pll pair<ll, ll>
char *SSSS, *TTTT;
char pori[1 << 22];
#define gc() (SSSS == TTTT && (TTTT = (SSSS = pori) + fread(pori, 1, 1 << 22, stdin)), SSSS == TTTT ? EOF : *SSSS++)
inline ll read()
{
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * f;
}
using namespace std;
const ll N=5e5+5,mod=1e9+7;
ll n,m,rt;
ll w[N],nw[N];
ll dep[N],sz[N],top[N],f[N],son[N],id[N],cnt;
vector<int> g[N];
struct node{
ll l,r;
ll lzy,tot;
}t[N<<2];
inline void dfs(ll u,ll fa,ll dp){
dep[u]=dp;
f[u]=fa;
sz[u]=1;
for (const int &v:g[u]){
if(v!=fa){
dfs(v,u,dp+1);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v]){
son[u]=v;
}
}
}
w[u]=sz[u];
}
inline void dfs2(ll u,ll tp){
id[u]=++cnt;
nw[cnt]=w[u];
top[u]=tp;
if(!son[u]){
return ;
}
dfs2(son[u],tp);
for (const int &v:g[u]){
if(v==f[u]||v==son[u]){
continue;
}
dfs2(v,v);
}
}
#define lc(p) (p<<1)
#define rc(p) (p<<1|1)
inline void pushup(ll p){
t[p].tot=(t[lc(p)].tot+t[rc(p)].tot)%mod;
}
inline void pushdown(ll p){
node &rt = t[p], &l = t[lc(p)], &r = t[rc(p)];
if (rt.lzy)
{
l.lzy += rt.lzy, l.tot += rt.lzy * (l.r - l.l + 1)%mod;
l.lzy %= mod, l.tot %= mod;
r.lzy += rt.lzy, r.tot += rt.lzy * (r.r - r.l + 1)%mod;
r.lzy %= mod, r.tot %= mod;
rt.lzy = 0;
}
}
inline void build(ll p,ll l,ll r){
t[p]=node{l,r,0,0};
if(l==r){
t[p].tot=nw[l];
return ;
}
ll mid=(l+r)>>1;
build(lc(p),l,mid);
build(rc(p),mid+1,r);
pushup(p);
}
inline void add(ll p,ll ql,ll qr,ll d){
if(ql<=t[p].l&&t[p].r<=qr){
t[p].lzy+=d;
t[p].lzy%=mod;
t[p].tot+=(t[p].r-t[p].l+1)*d%mod;
t[p].tot%=mod;
return ;
}
pushdown(p);
ll mid=(t[p].l+t[p].r)>>1;
if(ql<=mid){
add(lc(p),ql,qr,d);
}
if(mid<qr){
add(rc(p),ql,qr,d);
}
pushup(p);
}
inline ll query(ll p,ll ql,ll qr){
if(ql<=t[p].l&&t[p].r<=qr){
return t[p].tot;
}
pushdown(p);
ll mid=(t[p].l+t[p].r)>>1;
ll ret=0;
if(ql<=mid){
ret=(ret+query(lc(p),ql,qr))%mod;
}
if(mid<qr){
ret=(ret+query(rc(p),ql,qr))%mod;
}
return ret;
}
inline void updpath(ll u, ll v, ll d)
{
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]])
{
swap(u, v);
}
add(1, id[top[u]], id[u], d);
u = f[top[u]];
}
if (dep[u] < dep[v])
{
swap(u, v);
}
add(1, id[v], id[u], d);
}
inline ll querypath(ll u, ll v)
{
ll ret = 0;
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]])
{
swap(u, v);
}
ret += query(1, id[top[u]], id[u]);
ret%=mod;
u = f[top[u]];
}
if (dep[u] < dep[v])
{
swap(u, v);
}
ret += query(1, id[v], id[u]);
ret%=mod;
return ret;
}
pll a[N];
int main(){
n=read();
rep(i,2,n){
ll u=read(),v=read();
g[u].push_back(v);
g[v].push_back(u);
}
rt=1;
dfs(rt,-1,1);
dfs2(rt,rt);
build(1,1,n);
rep(i,1,n){
a[i]=mkp(read(),i);
}
sort(a+1,a+n+1,greater<pll>());
ll ans=0;
rep(i,1,n){
ll x=a[i].first,y=a[i].second;
ans=(ans+x*querypath(1,y)%mod)%mod;
updpath(1,y,-1);
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号