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


    树链剖分

    对树上的一条链加(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
    ",ans);
    		}
    	}
    	
    } 
    
  • 相关阅读:
    Java集合源码分析(一)
    EffectiveJava——请不要在代码中使用原生态类型
    Dubbo初探
    EffectiveJava——用函数对象表示策略
    EffectiveJava——类层次优于标签类
    notebook1.md
    NoteBook学习(二)-------- Zeppelin简介与安装
    Spark2.0学习(三)--------核心API
    Spark2.0学习(二)--------RDD详解
    Spark2.0学习(一)--------Spark简介
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/15050201.html
Copyright © 2020-2023  润新知