zoukankan      html  css  js  c++  java
  • (模板)树链剖分

    (模板)树链剖分

    大佬博客

    题目描述

    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

    操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

    操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

    操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

    操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

    • dfs1处理出重儿子,子树大小,父亲,深度
    • dfs2新标号,所在链顶端(用老标号)
    • 然后以新标号为下标开线段树

    代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cctype>
    #include <queue>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    inline int read()
    {
    	int x=0,f=1; char ch;
    	while(!isdigit(ch=getchar())) if(ch=='-') f=-1;
    	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    	return f*x;
    }
    typedef long long LL;
    #define res register int
    const int N=1e5+5;
    int head[N],ver[N<<1],nxt[N<<1];
    int n,m,tot,r;
    LL w[N],P;
    inline void add(int x,int y) { ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot;}
    
    int fa[N],dep[N],siz[N],son[N];
    /*
    Ê÷Á´ÆÊ·Ö£º
    1. dfs1 ´¦ÀíÉî¶È£¬Öضù×Ó£¬×ÓÊ÷´óС£¬¸¸Ç× 
    2. dfs2 бàºÅ£¬¸´ÖƵãȨ£¬¼Ç¼ÿÌõÖØÁ´µÄ¶¥¶Ë 
    3.Ï߶ÎÊ÷´¦ÀíÁ¬ÐøÇø¼äºÍ 
    */
    void dfs1(int x,int f)
    {
    	fa[x]=f; dep[x]=dep[f]+1;
    	siz[x]=1;
    	for(res i=head[x] ; i ; i=nxt[i])
    	{
    		int y=ver[i];
    		if(y==f) continue;
    		dfs1(y,x);
    		siz[x]+=siz[y];
    		if(siz[y]>siz[son[x]]) son[x]=y;
    	}
    }
    
    int num=0,id[N],top[N];
    LL val[N];
    void dfs2(int x,int topf)
    {
    	id[x]=++num; val[num]=w[x];
    	top[x]=topf;
    	if(!son[x]) return ;
    	dfs2(son[x],topf);//ÓÅÏÈ´¦ÀíÖضù×Ó 
    	for(res i=head[x] ; i ; i=nxt[i])
    	{
    		int y=ver[i]; if(y==son[x]||y==fa[x]) continue;
    		dfs2(y,y);
    	}
    }
    //Ï߶ÎÊ÷£º
    LL tag[N<<2],sum[N<<2];
    #define lson p<<1,l,mid
    #define rson p<<1|1,mid+1,r
    inline void pushup(int p)
    {sum[p]=(sum[p<<1]+sum[p<<1|1]+P)%P;}
    inline void build(int p,int l,int r)
    {
    	if(l==r) {
    		sum[p]=val[l]; return ;
    	}
    	int mid=(l+r)>>1;
    	build(lson); build(rson);
    	pushup(p);	
    }
    inline void pushdown(int p,int l,int r,int mid)
    {	
    	sum[p<<1]=(sum[p<<1]+(mid-l+1)*tag[p]+P)%P;
    	sum[p<<1|1]=(sum[p<<1|1]+(r-mid)*tag[p]+P)%P;
    	tag[p<<1]=(tag[p<<1]+tag[p]+P)%P;
    	tag[p<<1|1]=(tag[p<<1|1]+tag[p]+P)%P;
    	tag[p]=0;
    }
    
    inline LL query(int p,int l,int r,int ql,int qr)
    {
    	if(ql>qr) swap(ql,qr);
    	if(ql<=l && r<=qr) return sum[p];
    	int mid=(l+r)>>1;
    	pushdown(p,l,r,mid);
    	LL ret=0;
    	if(ql<=mid) ret=query(lson,ql,qr)%P;
    	if(qr>mid) ret=(query(rson,ql,qr)+P+ret)%P;
    	return ret;
    }
    
    inline void change(int p,int l,int r,int ql,int qr,LL k)
    {
    	if(qr<ql) swap(ql,qr);
    	if(ql<=l && r<=qr)
    	{
    		sum[p]+=(LL)(r-l+1)*k; 
    		tag[p]+=k;
    		return;
    	}
    	int mid=(l+r)>>1;
    	pushdown(p,l,r,mid);
    	if(ql<=mid) change(lson,ql,qr,k);
    	if(qr>mid) change(rson,ql,qr,k);
    	pushup(p);
    }
    //end 
    inline LL qson(int p) {
    	return query(1,1,n,id[p],id[p]+siz[p]-1);
    }
    inline void cson(int p,int k) {
    	change(1,1,n,id[p],id[p]+siz[p]-1,k);
    }
    //²éѯʱÏÈÕÒËùÔÚÁ´µÄ¶¥µã×îÉîµÄ£¬È»ºó²»¶ÏÍùÉÏÌø
    inline LL qrange(int x,int y)
    {
    	LL ret=0;
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);//ÈÃx¸üÉî
    		ret=(query(1,1,n,id[top[x]],id[x])+ret+P)%P;
    		x=fa[top[x]]; 
    	}
    	if(dep[x]<dep[y]) swap(x,y);
    	ret=(ret+P+query(1,1,n,id[y],id[x]))%P;
    	return ret;
    }
    
    inline void crange(int x,int y,int k)
    {
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		change(1,1,n,id[top[x]],id[x],k);
    		x=fa[top[x]];
    	}
    	if(dep[x]<dep[y]) swap(x,y);
    	change(1,1,n,id[y],id[x],k);
    }
    
    int main()
    {
    //	freopen("in.txt","r",stdin);
    	n=read(); m=read(); r=read(); P=read();
    	for(res i=1 ; i<=n ; ++i) w[i]=read();
    	for(res i=1 ; i<n ; ++i) {
    		int x=read(),y=read(); 
    		add(x,y); add(y,x);
    	}
    	dfs1(r,0);
    	dfs2(r,r); 
    	build(1,1,n);
    	int x,y,k,op;
    	for(res i=1 ; i<=m ; ++i)
    	{
    		op=read();
    		if(op==1)
    		{
    			x=read(); y=read(); k=read();
    			crange(x,y,k);
    		}
    		else if(op==2)
    		{
    			x=read(); y=read();
    			printf("%lld
    ",qrange(x,y));
    		}
    		else if(op==3)
    		{
    			x=read(); k=read();
    			cson(x,k); 
    		}
    		else
    		{
    			x=read(); 
    			printf("%lld
    ",qson(x));
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    LINQ N~layer!
    CodeSmith 破解和注册
    鼠标划过链接时弹出窗口
    ajax的loading显示在gridview的位置
    Asp.net与SQL一起打包部署安装
    编译apache报错 No recognized SSL/TLS toolkit detected
    ubuntu12.04 卸载和安装mysql
    Ubuntu12.04 英文环境下使用ibus输入中文并自动启动输入法
    Ubuntu11.10 源码编译安装PHP5.3.8 [转]
    debian 下 编译安装 mysql 二进制文件
  • 原文地址:https://www.cnblogs.com/wmq12138/p/10625187.html
Copyright © 2011-2022 走看看