• 洛谷 P3384树链剖分 题解


    题面

    挺好的一道树剖模板;

    首先要学会最模板的树剖;

    然后这道题要注意几个细节:

    初始化时,seg[0]=1,seg[root]=1,top[root]=root,rev[1]=root;

    在线段树上进行操作时,要使用lazy标记;

    对于一个以x为根的子树,它子树中所有的元素一定时在线段树上连续的区间,且以seg[x]开始,以seg[x]+size[x]-1结束;

    然后写码的时候注意不要手残(比如说预处理时写成了dep[u]=dep[u]+1);

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,r,p;
    int head[2000010],cnt;
    class littlestar{
    	public:
    		int to;
    		int nxt;
    		void add(int u,int v){
    			to=v;
    			nxt=head[u];
    			head[u]=cnt;		
    		}
    }star[2000010];
    int a[100010];
    int f[100010],dep[100010],son[100010],seg[100010],rev[100010],size[100010],top[100010];
    void dfs1(int u,int fa)
    {
    	size[u]=1;
    	f[u]=fa;
    	dep[u]=dep[fa]+1;
    	for(int i=head[u];i;i=star[i].nxt){
    		int v=star[i].to;
    		if(v==fa) continue;
    		dfs1(v,u);
    		size[u]+=size[v];
    		if(size[v]>size[son[u]]) son[u]=v;
    	}
    }
    void dfs2(int u,int fa)
    {
    	if(son[u]){
    		seg[son[u]]=++seg[0];
    		rev[seg[0]]=son[u];
    		top[son[u]]=top[u];
    		dfs2(son[u],u);
    	}
    	for(int i=head[u];i;i=star[i].nxt){
    		int v=star[i].to;
    		if(v==fa) continue;
    		if(!top[v]){
    			seg[v]=++seg[0];
    			rev[seg[0]]=v;
    			top[v]=v;
    			dfs2(v,u);
    		}
    	}
    }
    struct ss{
    	int sum;
    	int lazy;
    }tree[1000010];
    void build(int k,int l,int r)
    {
    	if(l==r){
    		tree[k].sum=a[rev[l]]%p;
    		return;
    	}
    	int mid=(l+r)/2;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
    }
    void pre()
    {
    	dfs1(r,0);
    	seg[0]=seg[r]=1;
    	top[r]=r;
    	rev[1]=r;
    	dfs2(r,0);
    	build(1,1,seg[0]);	
    }
    void pushdown(int k,int l,int r)
    {
    	int mid=(l+r)/2;
    	tree[k<<1].lazy=(tree[k<<1].lazy+tree[k].lazy)%p;
    	tree[k<<1].sum=(tree[k<<1].sum+tree[k].lazy*(mid-l+1))%p;
    	tree[k<<1|1].lazy=(tree[k<<1|1].lazy+tree[k].lazy)%p;
    	tree[k<<1|1].sum=(tree[k<<1|1].sum+tree[k].lazy*(r-mid))%p;
    	tree[k].lazy=0;
    }
    int query(int k,int l,int r,int x,int y)
    {
    	if(r<x||l>y){
    		return 0;
    	}
    	if(l>=x&&r<=y){
    		return tree[k].sum%p;
    	}
    	int mid=(l+r)/2;
    	pushdown(k,l,r);
    	return (query(k<<1,l,mid,x,y)+query(k<<1|1,mid+1,r,x,y))%p;
    }
    void change(int k,int l,int r,int x,int y,int goal)
    {
    	if(r<x||l>y) return;
    	if(l>=x&&r<=y){
    		tree[k].sum=(tree[k].sum+(r-l+1)*goal)%p;
    		tree[k].lazy=(tree[k].lazy+goal)%p;
    		return;
    	}
    	pushdown(k,l,r);
    	int mid=(l+r)/2;
    	change(k<<1,l,mid,x,y,goal);
    	change(k<<1|1,mid+1,r,x,y,goal);
    	tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%p;
    }
    void changeroad(int x,int y,int z)
    {
    	int fx=top[x],fy=top[y];
    	while(fx!=fy){
    		if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
    		change(1,1,seg[0],seg[fx],seg[x],z);
    		x=f[fx];
    		fx=top[x];
    	}
    	if(dep[x]>dep[y]) swap(x,y);
    	change(1,1,seg[0],seg[x],seg[y],z);
    }
    int queryroad(int x,int y)
    {
    	long long ans=0;
    	int fx=top[x],fy=top[y];
    	while(fx!=fy){
    		if(dep[fx]<dep[fy]) swap(fx,fy),swap(x,y);
    		ans=(ans+query(1,1,seg[0],seg[fx],seg[x]))%p;
    		x=f[fx];
    		fx=top[x];
    	}
    	if(dep[y]<dep[x]) swap(x,y);
    	ans=(ans+query(1,1,seg[0],seg[x],seg[y]))%p;
    	return ans%p;
    }
    void changetree(int x,int goal)
    {
    	change(1,1,seg[0],seg[x],seg[x]+size[x]-1,goal);
    	return;
    }
    long long querytree(int x)
    {
    	long long res=0;
    	res=(res+query(1,1,seg[0],seg[x],seg[x]+size[x]-1))%p;
    	return res;
    }
    int main(){
    	cin>>n>>m>>r>>p;
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	for(int i=1;i<=n-1;i++){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		star[++cnt].add(u,v);
    		star[++cnt].add(v,u);
    	}
    	pre();
    	for(int i=1;i<=m;i++){
    		int type;
    		scanf("%d",&type);
    		if(type==1){
    			int x,y,z;
    			scanf("%d%d%d",&x,&y,&z);
    			changeroad(x,y,z);
    		}
    		else if(type==2){
    			int x,y;
    			scanf("%d%d",&x,&y);
    			cout<<queryroad(x,y)%p<<endl;
    		}
    		else if(type==3){
    			int x,z;
    			scanf("%d%d",&x,&z);
    			changetree(x,z);
    		}
    		else{
    			int x;
    			scanf("%d",&x);
    			cout<<querytree(x)%p<<endl;
    		}
    	}
    }
    /*
    5 5 2 30000
    7 3 7 8 0 
    1 2
    1 5
    3 1
    4 1
    3 4 2
    3 2 2
    4 5
    1 5 1 3
    2 1 3
    */
    

     

  • 相关阅读:
    springboot 梳理2--配置druid数据源
    springboot 梳理1--简单整合mybatis
    springmvc 梳理13--@RequestBody 和 @ResponseBody
    springmvc 梳理12--拦截器
    springmvc 梳理11--restful
    如何快速成长为技术大牛?阿里资深技术专家的总结亮了
    一句话+一张图理解——数据结构与算法
    .net 开发人员的瓶颈和职业发展
    c# 对象相等性和同一性
    c# 连等的写法都做了什么?
  • 原文地址:https://www.cnblogs.com/kamimxr/p/11652696.html
Copyright © 2020-2023  润新知