首页 > 其他 > 详细

HDU6962 I Love Tree(2021HDU多校第二场1002)(线段树区间加幂和模型+树链剖分)

时间:2021-07-23 23:56:56      阅读:30      评论:0      收藏:0      [点我收藏+]

树链剖分

对树上的一条链加\(1^2,2^2,...n^2\)

每次询问单点。

我们设L是u和v的LCA。

那么对于链u->L,区间加上\((dep_u-dep_x+1)^2\)

即加上\((dep_x-dep_u-1)^2\)

对于链L->v,区间加上\((dep_u-dep_L+1+dep_x-dep_L)^2\)

\((dep_x-(2dep_L-dep_u-1))^2\)

这两步式子化出来之后,我们发现,就是对\(i \in [L,R]\)增加

\((a_i-x)^2=(a_i^2-2xa_i+x^2)\)

对于每次修改,区间内的x都是一样的。

对于式子的第一项,我们只需要维护每个位置\(a_i^2\)的个数即可,区间+1。

对于式子的第二项,我们需要维护\(a_i\)的个数,区间减2x即可。

对于式子的第三项,我们只需要区间\(+x^2\)即可。

这三项分别开S1 S2 S3三颗线段树维护即可。

最后答案就是S1的答案乘\(a_i^2\),S2的答案乘\(a_i\),S3的答案,求和即可。

时间复杂度\(O(nlognlogn)\)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int M=3e6+100;
typedef long long ll;
ll c[M],lz[M],lson[M],rson[M],tot,T[4];

int build (int l,int r) {
	int newRoot=++tot;
	c[newRoot]=lz[newRoot]=0;
	if (l==r) {
		return newRoot;
	}
	int mid=(l+r)>>1;
	lson[newRoot]=build(l,mid);
	rson[newRoot]=build(mid+1,r);
	return newRoot; 
}
void pushdown (int u,int l,int r) {
	if (lz[u]) {
		int mid=(l+r)>>1;
		c[lson[u]]+=1ll*(mid-l+1)*lz[u];
		lz[lson[u]]+=lz[u];
		
		c[rson[u]]+=1ll*(r-mid)*lz[u];
		lz[rson[u]]+=lz[u];
		
		lz[u]=0;
	}
}
void up (int u,int l,int r,int L,int R,ll v) {
	if (l>=L&&r<=R) {
		c[u]+=1ll*(r-l+1)*v;
		lz[u]+=v;
		return;
	}
	pushdown(u,l,r);
	int mid=(l+r)>>1;
	if (L<=mid) up(lson[u],l,mid,L,R,v);
	if (R>mid) up(rson[u],mid+1,r,L,R,v);
	c[u]=c[lson[u]]+c[rson[u]];
}
ll query (int u,int l,int r,int L,int R) {
	if (l>=L&&r<=R) return c[u];
	pushdown(u,l,r);
	int mid=(l+r)>>1;
	ll ans=0;
	if (L<=mid) ans+=query(lson[u],l,mid,L,R);
	if (R>mid) ans+=query(rson[u],mid+1,r,L,R);
	return ans;
}
int n;
void AddHs (int l,int r,ll x) {
	//区间加上(a_i-x)^2
	up(T[1],1,n,l,r,1);
	up(T[2],1,n,l,r,-2ll*x);
	up(T[3],1,n,l,r,1ll*x*x); 
}

vector<int> g[maxn];
int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],sz[maxn],top[maxn];
int lca (int x,int y) {
	for (;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
	return dep[x]<dep[y]?x:y;
}
void upRange (int x,int y) {
	int L=lca(x,y);
	int A=dep[x];
	int C=dep[L];
	while (top[x]!=top[y]) {
		if (dep[top[x]]<dep[top[y]]) {
			AddHs(id[top[y]],id[y],(2ll*C-A-1));
			y=fa[top[y]];
		}
		else {
			AddHs(id[top[x]],id[x],A+1);
			x=fa[top[x]];	
		}
	}
	if (dep[x]>=dep[y]) {
		AddHs(id[y],id[x],A+1);
	}
	else {
		AddHs(id[x],id[y],(2ll*C-A-1));
	}
}
void dfs1 (int x,int f,int deep) {
	dep[x]=deep;
	fa[x]=f;
	sz[x]=1;
	int maxson=-1;
	for (int y:g[x]) {
		if (y==f) continue;
		dfs1(y,x,deep+1);
		sz[x]+=sz[y];
		if (sz[y]>maxson) {
			son[x]=y;
			maxson=sz[y];
		}
	}
}
void dfs2 (int x,int topf) {
	id[x]=++cnt;
	top[x]=topf;
	if (!son[x]) return;
	dfs2(son[x],topf);
	for (int y:g[x]) {
		if (y==fa[x]||y==son[x]) continue;
		dfs2(y,y);
	}
}
int main () {
	scanf("%d",&n);
	for (int i=1;i<n;i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		g[x].push_back(y);
		g[y].push_back(x);
	}
	
	dfs1(1,0,1);
	dfs2(1,1);
	for (int i=1;i<=3;i++) T[i]=build(1,n);
	int q;
	scanf("%d",&q);
	while (q--) {
		int op;
		scanf("%d",&op);
		if (op==1) {
			int x,y;
			scanf("%d%d",&x,&y);
			upRange(x,y);
		}
		else {
			int x;
			scanf("%d",&x);
			ll ans=1ll*dep[x]*dep[x]*query(T[1],1,n,id[x],id[x])+1ll*dep[x]*query(T[2],1,n,id[x],id[x])+query(T[3],1,n,id[x],id[x]);
			printf("%lld\n",ans);
		}
	}
	
} 

HDU6962 I Love Tree(2021HDU多校第二场1002)(线段树区间加幂和模型+树链剖分)

原文:https://www.cnblogs.com/zhanglichen/p/15050201.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!