zoukankan      html  css  js  c++  java
  • [SHOI2012]魔法树

    题目:洛谷P3833。

    题目大意:给你一棵树,有两种操作:1.给两个点和它们之间的最短路上的所有点加上一个值;2.询问以某个点为根的子树的子树和。你需要实现这个功能。

    解题思路:如果只有最后才询问的话,本题可以用树上差分做。然而询问和修改是穿插的。

    那么我们只能使用树链剖分了。

    用树剖则很简单,修改就是边求lca边维护线段树。查询则是线段树区间查询。

    由于本题从0开始编号,把每个点的编号+1,就变成从1开始编号(主要是因为习惯)。

    时间复杂度$O(Qlog^2 n)$。

    C++ Code:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #define N 100005
    #define ll long long
    int n,head[N],cnt,sz[N],dep[N],son[N],top[N],fa[N],dfn[N],idx,t,L,R;
    ll ans;
    struct edge{
    	int to,nxt;
    }e[N<<1];
    struct SegmentTreeNode{
    	ll s,add;
    }d[N<<2];
    inline int readint(){
    	char c=getchar();
    	for(;!isdigit(c);c=getchar());
    	int d=0;
    	for(;isdigit(c);c=getchar())
    	d=(d<<3)+(d<<1)+(c^'0');
    	return d;
    }
    void dfs(int now){
    	sz[now]=1;
    	for(int i=head[now];i;i=e[i].nxt)
    	if(!dep[e[i].to]){
    		dep[e[i].to]=dep[now]+1;
    		fa[e[i].to]=now;
    		dfs(e[i].to);
    		sz[now]+=sz[e[i].to];
    		if(!son[now]||sz[son[now]]<sz[e[i].to])son[now]=e[i].to;
    	}
    }
    void dfs2(int now){
    	dfn[now]=++idx;
    	if(son[now])top[son[now]]=top[now],dfs2(son[now]);
    	for(int i=head[now];i;i=e[i].nxt)
    	if(e[i].to!=son[now]&&dep[now]<dep[e[i].to])
    	top[e[i].to]=e[i].to,dfs2(e[i].to);
    }
    inline void pushdown(int o,int len){
    	int ld=o<<1,rd=o<<1|1;
    	d[ld].add+=d[o].add;
    	d[ld].s+=d[o].add*((len+1)>>1);
    	d[rd].add+=d[o].add;
    	d[rd].s+=d[o].add*(len>>1);
    	d[o].add=0;
    }
    void addt(int l,int r,int o){
    	if(L<=l&&r<=R){
    		d[o].add+=t;
    		d[o].s+=(ll)t*(r-l+1);
    	}else{
    		pushdown(o,r-l+1);
    		int mid=(l+r)>>1;
    		if(L<=mid)addt(l,mid,o<<1);
    		if(mid<R)addt(mid+1,r,o<<1|1);
    		d[o].s=d[o<<1].s+d[o<<1|1].s;
    	}
    }
    void add(int x,int y){
    	for(;top[x]!=top[y];)
    	if(dep[top[x]]>=dep[top[y]]){
    		L=dfn[top[x]],R=dfn[x];
    		addt(1,n,1);
    		x=fa[top[x]];
    	}else{
    		L=dfn[top[y]],R=dfn[y];
    		addt(1,n,1);
    		y=fa[top[y]];
    	}
    	if(dep[x]<=dep[y])L=dfn[x],R=dfn[y];else
    	L=dfn[y],R=dfn[x];
    	addt(1,n,1);
    }
    void query(int l,int r,int o){
    	if(L<=l&&r<=R)ans+=d[o].s;else{
    		pushdown(o,r-l+1);
    		int mid=(l+r)>>1;
    		if(L<=mid)query(l,mid,o<<1);
    		if(mid<R)query(mid+1,r,o<<1|1);
    	}
    }
    int main(){
    	n=readint();
    	cnt=idx=0;
    	for(int i=1;i<n;++i){
    		int u=readint()+1,v=readint()+1;
    		e[++cnt]=(edge){v,head[u]};
    		head[u]=cnt;
    		e[++cnt]=(edge){u,head[v]};
    		head[v]=cnt;
    	}
    	dep[1]=top[1]=fa[1]=1;
    	dfs(1);dfs2(1);
    	memset(d,0,sizeof d);
    	for(int q=readint();q--;){
    		char c=getchar();
    		while(!isalpha(c))c=getchar();
    		if(c=='A'){
    			int x=readint()+1,y=readint()+1;t=readint();
    			add(x,y);
    		}else{
    			int u=readint()+1;
    			L=dfn[u],R=dfn[u]+sz[u]-1;
    			ans=0;
    			query(1,n,1);
    			printf("%lld
    ",ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    如何在Windows Forms应用程序中实现可组装式(Composite)的架构以及松耦合事件机制
    SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑
    【VSTO】Office开发中遇到的兼容性检查问题
    SQL Server 2008 R2的StreamInsight 【文章转载】
    WCF技术的不同应用场景及其实现分析
    如何利用Interception简化MVVM中的Model和ViewModel的设计
    有关在SharePoint Server中Infopath表单无法呈现的问题及解决方案
    再谈谈ADO.NET Data Service 数据格式(xml和json)
    自定义Domain Service时遇到实体不能更新的问题及其解决方案
    如何在RIA Service中启用身份验证
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7966392.html
Copyright © 2011-2022 走看看