CF960H Santa's Gift
注:为了避免混淆,修改了部分变量的名称。
- 给出 \(n\) 个点的有根树,\(m\) 种颜色,点 \(i\) 有颜色 \(a_i\),颜色 \(i\) 有权值 \(b_i\)。维护两种操作,共 \(q\) 次:
\(\texttt{1 }x\text{ }y\),将 \(a_x\leftarrow y\)。
\(\texttt{2 }x\),从树中等概率选取一个点 \(i\),得到 \((S_i\times b_x-C)^2\) 的价值。求期望价值。其中 \(S_i\) 表示以 \(i\) 为根的子树中颜色为 \(x\) 的节点数。\(C\) 是给定的常数。
- \(n,m\le 5\times 10^4\)。
先写出答案的表达式:
\[\begin{aligned}\dfrac{\sum_{i=1}^n(S_i\times b_x-C)^2}{n}&=\dfrac{\sum_{i=1}^n(b_x^2S_i^2-2b_xCS_i+C^2)}{n}\\&=\dfrac{b_x^2\sum_{i=1}^n S_i^2-2b_xC\sum_{i=1}^nS_i+nC^2}{n}\end{aligned}
\]
考虑维护每种颜色的 \(S_i\),套路树剖再动态开点线段树。操作 \(\texttt{1}\) 相当于对颜色 \(a_x\) 将根到 \(x\) 路径上的 \(S_i\) 减 \(1\),对于颜色 \(y\) 将这些 \(S_i\) 加 \(1\)。这个修改区间含根节点很友好,不需要正常跳链,直接从 \(x\) 跳到根就好了。
线段树的节点要维护平方和以及和,简单讲一下平方和的维护:
\[\begin{aligned}\sum\limits_{i=l}^r(x_i+v)^2&=\sum\limits_{i=l}^r(x_i^2+2vx_i+v^2)\\&=\sum\limits_{i=l}^rx_i^2+2v\sum\limits_{i=l}^rx_i+(r-l+1)v^2\end{aligned}
\]
就是在原来平方和的基础上加上 \(2v\) 倍的原来的和,再加上 \((r-l+1)v^2\)。由于是动态开点线段树不方便 pushdown,所以写了标记永久化。
对于 \(\texttt{2}\) 操作,查询区间为 \([1,n]\) 也很友好,直接用那种颜色线段树的根的信息就可以了。
时空复杂度均为 \(\mathcal{O}(m\log^2n)\),可以接受。
$\color{orange}\bf点击查看代码$
//指针预警/cf。
#include<bits/stdc++.h>
#define ls x->lc
#define rs x->rc
#define int long long
using namespace std;
const int N=5e4+5;
int n,m,q,c,a[N],b[N],f[N],sz[N],d[N],t[N],h[N],dfn[N],cnt;
vector<int>g[N];
struct node{
int sum,sq,add;
node*lc,*rc;
node(){
sum=sq=add=0;
lc=rc=NULL;
}
}*rt[N];
void dfs1(int u){
sz[u]=1;
for(int v:g[u]){
d[v]=d[u]+1;
dfs1(v);
sz[u]+=sz[v];
}
}
void dfs2(int u){
for(int v:g[u]){
if((sz[v]<<1ll)>sz[u]){
t[h[u]=v]=t[u];
}else{
t[v]=v;
}
dfs2(v);
}
}
void dfs3(int u){
dfn[u]=++cnt;
if(h[u]){
dfs3(h[u]);
}
for(int v:g[u]){
if(v^h[u]){
dfs3(v);
}
}
}
void modify(node*&x,int l,int r,int ql,int qr,int k){
if(x==NULL){
x=new node;
}
if(ql<=l&&r<=qr){
x->add+=k;
x->sq+=2*k*x->sum+(r-l+1)*k*k;
x->sum+=(r-l+1)*k;
}else{
int mid=(l+r)>>1ll;
if(ql<=mid){
modify(ls,l,mid,ql,qr,k);
}
if(qr>mid){
modify(rs,mid+1,r,ql,qr,k);
}
x->sum=x->sq=0;
if(ls!=NULL){
x->sum+=ls->sum;
x->sq+=ls->sq;
}
if(rs!=NULL){
x->sum+=rs->sum;
x->sq+=rs->sq;
}
x->sq+=2*x->add*x->sum+(r-l+1)*x->add*x->add;
x->sum+=(r-l+1)*x->add;
}
}
void chain(int k,int x,int v){
while(x){
modify(rt[k],1,n,dfn[t[x]],dfn[x],v);
x=f[t[x]];
}
}
signed main(){
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin>>n>>m>>q>>c;
for(int i=1;i<=n;++i){
cin>>a[i];
}
for(int i=2;i<=n;++i){
cin>>f[i];
g[f[i]].emplace_back(i);
}
for(int i=1;i<=m;++i){
rt[i]=NULL;
cin>>b[i];
}
dfs1(1);
dfs2(t[1]=1);
dfs3(1);
for(int i=1;i<=n;++i){
chain(a[i],i,1);
}
for(int op,x,y;q--;){
cin>>op>>x;
if(op&1ll){
cin>>y;
chain(a[x],x,-1);
chain(a[x]=y,x,1);
}else{
if(rt[x]==NULL){//无这种颜色。
cout<<c*c<<'\n';
}else{
cout<<fixed<<setprecision(12)<<(1.0*b[x]*b[x]*rt[x]->sq-1.0*2*b[x]*c*rt[x]->sum+n*c*c)/n<<'\n';
}
}
}
}

浙公网安备 33010602011771号