标签:连通 query long def memset wap span mit modify
题意:一棵带点权的树,支持修改点权和查询,查询$(u,v)$时答案为$\sum\limits_{(i,j)\cap(u,v)\ne\varnothing}v_iv_j$
路径交不为空不好处理,考虑转为全部减去路径交为空
全部就是$\sum\limits_i\sum\limits_jv_iv_j=\left(\sum\limits_iv_i\right)^2$
路径交为空就是删去$(u,v)$后剩下的许多连通块中的$\left(\sum\limits_iv_i\right)^2$之和
设$s_x=\sum\limits_{i\in\text{sub}(x)}v_i$,考虑用树剖维护每个点$x$的信息$\sum\limits_{u\in\text{light}(x)}s_u^2$,那么总答案就是链上这些信息之和减去跳重链时经过的链顶的$s_x^2$再加上跳重链时被忽略的重儿子$s_x^2$,最后加上$(s_x-s_{\text{lca}})^2$
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1000000007;
int mul(int a,int b){return a*(ll)b%mod;}
int sqr(int x){return x*(ll)x%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
void inc(int&a,int b){(a+=b)%=mod;}
void dec(int&a,int b){(a-=b)%=mod;}
struct seg{
int T[400010],M;
void modify(int x,int v){
inc(T[x+=M],v);
for(x>>=1;x;x>>=1)T[x]=ad(T[x<<1],T[x<<1|1]);
}
int query(int s,int t){
int res=0;
for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){
if(~s&1)inc(res,T[s^1]);
if(t&1)inc(res,T[t^1]);
}
return res;
}
}t1,t2;
int h[100010],nex[200010],to[200010],v[100010],M;
void add(int a,int b){
M++;
to[M]=b;
nex[M]=h[a];
h[a]=M;
}
int fa[100010],siz[100010],dep[100010],son[100010],bl[100010],pos[100010],s[100010];
void dfs(int x){
int i,k=0;
siz[x]=1;
dep[x]=dep[fa[x]]+1;
s[x]=v[x];
for(i=h[x];i;i=nex[i]){
if(to[i]!=fa[x]){
fa[to[i]]=x;
dfs(to[i]);
siz[x]+=siz[to[i]];
inc(s[x],s[to[i]]);
if(siz[to[i]]>siz[k])k=to[i];
}
}
son[x]=k;
}
void dfs(int x,int chain){
pos[x]=++M;
bl[x]=chain;
if(son[x])dfs(son[x],chain);
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa[x]&&to[i]!=son[x])dfs(to[i],to[i]);
}
}
int query(int x){
return t1.query(pos[x],pos[x]+siz[x]-1);
}
void modify(int x,int v){
int t;
while(x){
if(fa[bl[x]]){
t=query(bl[x]);
t2.modify(pos[fa[bl[x]]],ad(mul(2,mul(v,t)),sqr(v)));
}
x=fa[bl[x]];
}
}
int lca(int x,int y){
while(bl[x]!=bl[y]){
if(dep[bl[x]]<dep[bl[y]])swap(x,y);
x=fa[bl[x]];
}
return dep[x]<dep[y]?x:y;
}
int query(int x,int y){
int l=lca(x,y),res=0,pr;
pr=0;
while(bl[x]!=bl[l]){
inc(res,ad(de(t2.query(pos[bl[x]],pos[x]),pr),son[x]?sqr(query(son[x])):0));
pr=sqr(query(bl[x]));
x=fa[bl[x]];
}
dec(res,pr);
pr=0;
while(bl[y]!=bl[l]){
inc(res,ad(de(t2.query(pos[bl[y]],pos[y]),pr),son[y]?sqr(query(son[y])):0));
pr=sqr(query(bl[y]));
y=fa[bl[y]];
}
dec(res,pr);
if(dep[x]>dep[y])swap(x,y);
if(son[y])inc(res,sqr(query(son[y])));
inc(res,t2.query(pos[x],pos[y]));
inc(res,sqr(de(t1.T[1],query(x))));
res=de(sqr(t1.T[1]),res);
return ad(res,mod);
}
int main(){
int n,m,i,x,y;
while(~scanf("%d%d",&n,&m)){
M=0;
memset(h,0,sizeof(h));
memset(t1.T,0,sizeof(t1.T));
memset(t2.T,0,sizeof(t2.T));
for(i=1;i<=n;i++)scanf("%d",v+i);
for(i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1);
M=0;
dfs(1,1);
for(M=1;M<=n+1;M<<=1);
t1.M=t2.M=M;
for(i=1;i<=n;i++)t1.T[pos[i]+M]=v[i];
for(i=M-1;i>0;i--)t1.T[i]=ad(t1.T[i<<1],t1.T[i<<1|1]);
for(x=1;x<=n;x++){
y=0;
for(i=h[x];i;i=nex[i]){
if(to[i]!=son[x]&&to[i]!=fa[x])inc(y,sqr(s[to[i]]));
}
t2.T[pos[x]+M]=y;
}
for(i=M-1;i>0;i--)t2.T[i]=ad(t2.T[i<<1],t2.T[i<<1|1]);
while(m--){
scanf("%d%d%d",&i,&x,&y);
if(i==1){
dec(y,v[x]);
modify(x,y);
t1.modify(pos[x],y);
inc(v[x],y);
}else
printf("%d\n",query(x,y));
}
}
}
标签:连通 query long def memset wap span mit modify
原文地址:https://www.cnblogs.com/jefflyy/p/9418202.html