zoukankan      html  css  js  c++  java
  • [BZOJ3683]Falsita

    [BZOJ3683]Falsita

    题目大意:

    一个(n(nle3 imes10^5))个结点的树,每个结点有一个权值(w_i)(m(mle3 imes10^5))次操作,操作包含以下(3)种:

    1. 将结点(u)的权值加上(d)
    2. 将以(u)为根的子树中的每一个结点加上(d)
    3. 询问任取一个以(u)为LCA的点对((x,y))(w_x+w_y)的期望值。

    思路:

    首先可以用一遍树形DP求出不考虑修改的答案(ans_i)

    对于操作(1),会对(u)本身的答案产生(d imes(size[u]-1))的贡献。对(par[u])到根上每个结点(x)的贡献为(d imes(size[x]-size[y])),其中(y)(x)在链上的子结点。

    对于操作(2),会对(u)子树内每个结点产生(2d imes pair[x])的贡献,其中(pair[u])为以(u)为LCA的点对数。对到根的链上结点贡献为(d imes(size[x]-size[y]) imes size[u])

    由于对于每个结点,((size[x]-size[y]))(pair[x])都是固定的,因此对于链上修改和子树修改,我们只需要维护(d)即可。这可以用树链剖分+线段树实现。

    时间复杂度(mathcal O(nlog^2n))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<vector>
    inline int getint() {
    	register char ch;
    	register bool neg=false;
    	while(!isdigit(ch=getchar())) neg|=ch=='-';
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return neg?-x:x;
    }
    inline char getalpha() {
    	register char ch;
    	while(!isalpha(ch=getchar()));
    	return ch;
    }
    typedef long long int64;
    const int N=3e5+1;
    int par[N],w[N],size[N],dep[N],son[N],dfn[N],top[N];
    int64 pair[N],ans[N],sum[N];
    std::vector<int> e[N];
    inline void add_edge(const int &u,const int &v) {
    	e[u].push_back(v);
    }
    void dfs(const int &x,const int &par) {
    	size[x]=1;
    	sum[x]=w[x];
    	dep[x]=dep[par]+1;
    	for(unsigned i=0;i<e[x].size();i++) {
    		const int &y=e[x][i];
    		dfs(y,x);
    		sum[x]+=sum[y];
    		pair[x]+=1ll*size[x]*size[y];
    		size[x]+=size[y];
    		if(size[y]>size[son[x]]) {
    			son[x]=y;
    		}
    	}
    	ans[x]=1ll*w[x]*(size[x]-1);
    	for(register unsigned i=0;i<e[x].size();i++) {
    		const int &y=e[x][i];
    		ans[x]+=1ll*sum[y]*(size[x]-size[y]);
    	}
    }
    void dfs(const int &x) {
    	dfn[x]=++dfn[0];
    	top[x]=x==son[par[x]]?top[par[x]]:x;
    	if(son[x]) dfs(son[x]);
    	for(unsigned i=0;i<e[x].size();i++) {
    		const int &y=e[x][i];
    		if(y==son[x]) continue;
    		dfs(y);
    	}
    }
    class SegmentTree {
    	#define _left <<1
    	#define _right <<1|1
    	#define mid ((b+e)>>1)
    	private:
    		int64 val[N<<2];
    	public:
    		void add(const int &p,const int &b,const int &e,const int &l,const int &r,const int64 &d) {
    			if(b==l&&e==r) {
    				val[p]+=d;
    				return;
    			}
    			if(l<=mid) add(p _left,b,mid,l,std::min(mid,r),d);
    			if(r>mid) add(p _right,mid+1,e,std::max(mid+1,l),r,d);
    		}
    		int64 query(const int &p,const int &b,const int &e,const int &x) const {
    			int64 ret=val[p];
    			if(b==e) return ret;
    			if(x<=mid) ret+=query(p _left,b,mid,x);
    			if(x>mid) ret+=query(p _right,mid+1,e,x);
    			return ret;
    		}
    	#undef _left
    	#undef _right
    	#undef mid
    };
    SegmentTree t1,t2;
    inline void modify0(int x,const int64 &d) {
    	//链上修改
    	while(x) {
    		if(x!=top[x]) t1.add(1,1,dfn[0],dfn[top[x]],dfn[par[x]],d);
    		x=top[x];
    		if(par[x]!=0) ans[par[x]]+=d*(size[par[x]]-size[x]);
    		x=par[x];
    	}
    }
    inline void modify1(int x,const int64 &d) {
    	//单点修改
    	ans[x]+=d*(size[x]-1);
    	modify0(x,d);
    }
    inline void modify2(const int &x,const int64 &d) {
    	//子树修改
    	if(size[x]>1) t2.add(1,1,dfn[0],dfn[x],dfn[x]+size[x]-1,d);
    	modify0(x,d*size[x]);
    }
    inline double query(const int &x) {
    	return 1.*(ans[x]+1ll*t1.query(1,1,dfn[0],dfn[x])*(size[x]-size[son[x]])+2ll*t2.query(1,1,dfn[0],dfn[x])*pair[x])/pair[x];
    }
    int main() {
    	const int n=getint(),m=getint();
    	for(register int i=2;i<=n;i++) {
    		add_edge(par[i]=getint(),i);
    	}
    	for(register int i=1;i<=n;i++) {
    		w[i]=getint();
    	}
    	dfs(1,0);
    	dfs(1);
    	for(register int i=0;i<m;i++) {
    		const char opt=getalpha();
    		const int u=getint();
    		if(opt=='S') modify1(u,getint());
    		if(opt=='M') modify2(u,getint());
    		if(opt=='Q') printf("%.6f
    ",query(u));
    	}
    	return 0;
    }
    
  • 相关阅读:
    20145219《信息安全系统设计基础》实验二 固件开发
    20145219 《信息安全系统设计基础》第09周学习总结
    20145219 《信息安全系统设计基础》实验一 开发环境的熟悉
    20145219 《信息安全系统设计基础》期中总结
    20145219 《信息安全系统设计基础》第07周学习总结
    20145219 《信息安全系统设计基础》第06周学习总结
    20145219 《信息安全系统设计基础》第05周学习总结
    20145219 《信息安全系统设计基础》第03周学习总结
    20145219 《信息安全系统设计基础》第02周学习总结
    20145219 《信息安全系统设计基础》第01周学习总结
  • 原文地址:https://www.cnblogs.com/skylee03/p/10170612.html
Copyright © 2011-2022 走看看