[HDU5405]Sometimes Naive

题意:一棵带点权的树,支持修改点权和查询,查询$(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));
		}
	}
}

猜你喜欢

转载自www.cnblogs.com/jefflyy/p/9418202.html