标签:连通 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