zoukankan      html  css  js  c++  java
  • 树剖小结(简述)

    比较恶心,特别是线段树
    题目链接:P3384 【模板】重链剖分
    详解见:大佬博客
    我的代码:

    (Code):

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int MAXN=100005;
    int mod,n,m,root;
    int f[MAXN],dep[MAXN],son[MAXN],tot[MAXN];
    int t[MAXN],b[MAXN],id[MAXN],c=0,top[MAXN];
    struct edge
    {
    	int to,nxt;
    }e[MAXN<<1];
    int head[MAXN],cnt=0;
    void swap(int *a,int *b){int t=*a;*a=*b,*b=t;}
    void add(int u,int v)
    {
    	e[++cnt].to=v;
    	e[cnt].nxt=head[u];
    	head[u]=cnt;
    }
    int dfs1(int cur,int fa,int deep)
    {
    	dep[cur]=deep;
    	f[cur]=fa;
    	int maxn=-1;
    	tot[cur]=1;
    	for(int i=head[cur];i;i=e[i].nxt)
    	{
    		int j=e[i].to;
    		if(!(j^fa)) continue;
    		tot[cur]+=dfs1(j,cur,deep+1);
    		if(tot[j]>maxn) maxn=tot[j],son[cur]=j;
    	}
    	return tot[cur];
    }
    void dfs2(int cur,int topf)
    {
    	id[cur]=++c;
    	t[c]=b[cur];
    	top[cur]=topf;
    	if(!son[cur]) return;
    	dfs2(son[cur],topf);
    	for(int i=head[cur];i;i=e[i].nxt)
    	{
    		int j=e[i].to;
    		if(!id[j]) dfs2(j,j);
    	}
    }
    struct node
    {
    	int l,r,sum,lazy;
    	node()
    	{
    		l=r=sum=lazy=0;
    	}
    }a[MAXN<<2];
    void update(int k){a[k].sum=(a[k<<1].sum+a[k<<1|1].sum)%mod;}
    void build(int k,int l,int r)
    {
    	int mid=(l+r)>>1;
    	a[k].l=l,a[k].r=r;
    	if(l==r)
    	{
    		a[k].sum=t[l];
    		return;
    	}
    	build(k<<1,l,mid),build(k<<1|1,mid+1,r);
    	update(k);
    }
    void lazydown(int k)
    {
    	if(a[k].l==a[k].r)
    	{
    		a[k].lazy=0;
    		return;
    	}
    	a[k<<1].sum=(a[k<<1].sum+(a[k<<1].r-a[k<<1].l+1)*a[k].lazy%mod)%mod;
    	a[k<<1|1].sum=(a[k<<1|1].sum+(a[k<<1|1].r-a[k<<1|1].l+1)*a[k].lazy%mod)%mod;
    	a[k<<1].lazy=(a[k<<1].lazy+a[k].lazy)%mod;
    	a[k<<1|1].lazy=(a[k<<1|1].lazy+a[k].lazy)%mod;
    	a[k].lazy=0;
    }
    void change(int k,int l,int r,int x)
    {
    	int mid=(a[k].l+a[k].r)>>1;
    	if(a[k].l==l&&a[k].r==r)
    	{
    		a[k].sum=(a[k].sum+(a[k].r-a[k].l+1)*x%mod)%mod;
    		a[k].lazy=(a[k].lazy+x)%mod;
    		return;
    	}
    	if(a[k].lazy) lazydown(k);
    	if(r<=mid) change(k<<1,l,r,x);
    	else if(l>mid) change(k<<1|1,l,r,x);
    	else change(k<<1,l,mid,x),change(k<<1|1,mid+1,r,x);
    	update(k);
    }
    int query(int k,int l,int r)
    {
    	int mid;
    	if(a[k].lazy) lazydown(k);
    	if(a[k].l==l&&a[k].r==r) return a[k].sum%mod;
    	mid=(a[k].l+a[k].r)>>1;
    	if(r<=mid) return query(k<<1,l,r)%mod;
    	if(l>=mid+1) return query(k<<1|1,l,r)%mod;
    	return (query(k<<1,l,mid)+query(k<<1|1,mid+1,r))%mod;
    }
    void tree_add(int l,int r,int x)
    {
    	while(top[l]!=top[r])
    	{
    		if(dep[top[l]]<dep[top[r]]) swap(l,r);
    		change(1,id[top[l]],id[l],x);
    		l=f[top[l]];
    	}
    	if(dep[l]>dep[r]) swap(l,r);
    	change(1,id[l],id[r],x);
    	return;
    }
    
    int tree_query(int l,int r)
    {
    	int ans=0;
    	while(top[l]!=top[r])
    	{
    		if(dep[top[l]]<dep[top[r]]) swap(l,r);
    		ans=(ans+query(1,id[top[l]],id[l]))%mod;
    		l=f[top[l]];
    	}
    	if(dep[l]>dep[r]) swap(l,r);
    	ans=(ans+query(1,id[l],id[r]))%mod;
    	return ans%mod;
    }
    void son_add(int k,int x){change(1,id[k],id[k]+tot[k]-1,x);}
    int son_query(int k){return query(1,id[k],id[k]+tot[k]-1);} 
    int u,v,flag,x,y,z;
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&root,&mod);
    	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    	for(int i=1;i<n;i++)
    	{
    		scanf("%d%d",&u,&v);
    		add(u,v);
    		add(v,u);
    	}
    	dfs1(root,root,1);
    	dfs2(root,root);
    	build(1,1,n);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&flag,&x);
    		if(flag==1)
    		{
    			scanf("%d%d",&y,&z);
    			tree_add(x,y,z);
    		}
    		else if(flag==2)
    		{
    			scanf("%d",&y);
    			printf("%d
    ",tree_query(x,y)%mod);
    		}
    		else if(flag==3)
    		{
    			scanf("%d",&y);
    			son_add(x,y);
    		}
    		else printf("%d
    ",son_query(x)%mod);
    	}
    	return 0;
    }
    

    还是写炸了线段树,因为左右端点反了只有(30pts)(数据水?)
    还看了(bi)站视频,
    主要思想是根据(dfs)序使链和子树映射在线段树上,使得计算的相关点重新编号后在一个区间中,可证明时间复杂度为(O(mlog^2n))似乎懂了
    就这样

  • 相关阅读:
    php目录递归删除
    php嵌套数据
    HTML 标签
    枚举 递归
    传值传址 结构体
    去超市选择要购买的商品 将数组放入集合
    函数
    集合 ArrayList 类
    特殊集合 Stack Queue Hashtable
    二维数组,多维数组
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12264844.html
Copyright © 2011-2022 走看看