树剖 学习笔记与例题与模板

14 篇文章 0 订阅
6 篇文章 1 订阅

首先就是7个树剖要用到的数组:
fa[i]:i的父亲
dep[i]:i的深度
size[i]:以i为根的子树的大小
son[i]:i的重儿子编号
top[i]:i所在链的顶端节点编号
dfn[i]:i的dfs序编号
rnk[i]:dfs序中第i个枚举节点的编号
显而易见,有rnk[dfn[i]]=i;

什么花花绿绿的功能咱先不说,先把这7个数组求出来。
方法是DFS*2;

DFS1:求fa,dep,size,son.

dep[1]=1;
dfs1(1);
void dfs1(int st)
{
	son[st]=-1;
	size[st]=1;
	for(int i=head[st];i!=-1;i=e[i].ne)
	{
		if(dep[e[i].to]==0)
		{
			dep[e[i].to]=dep[st]+1;
			fa[e[i].to]=st;
			dfs1(e[i].to);
			size[st]+=size[e[i].to];
			if(son[st]==-1||size[e[i].to]>size[son[st]]) son[st]=e[i].to;
		}
	}
}

DFS2:求top,dfn,rnk.

cnt=0;
dfs2(1,1);
void dfs2(int st,int ft)
{
	top[st]=ft;
	cnt++;
	dfn[st]=cnt;
	rnk[cnt]=st;
	if(son[st]==-1) return;
	dfs2(son[st],ft);
	for(int i=head[st];i!=-1;i=e[i].ne)
	{
		if(e[i].to==son[st]||e[i].to==fa[st]) continue;
		dfs2(e[i].to,e[i].to);
	}
}

So,we can learn another skill about it.
LCA!!!
Tarjan,倍增,朴素,动态树,RMQ…
都没用了。。。
预处理O(n),单次查询O(log2n)。

int lca(int u,int v)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]>dep[top[v]])
		{
			u=fa[top[u]];
		}
		else
		{
			v=fa[top[v]];
		}
	}
	if(dep[u]>dep[v])
	{
		return v;
	}
	else
	{
		return u;
	}
}

最后就是最关键的一个技能了。
维护点与子树。

2256. 【ZJOI2008】树的统计 (Standard IO)
Time Limits: 2000 ms Memory Limits: 512000 KB Detailed Limits
Description
  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
  我们将以下面的形式来要求你对这棵树完成一些操作:
  I. CHANGE u t : 把结点u的权值改为t
  II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
  III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
  注意:从点u到点v的路径上的节点包括u和v本身
Input
  输入文件的第一行为一个整数n,表示节点的个数。
  接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
  接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
  接下来1行,为一个整数q,表示操作的总数。
  接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
Output
  对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16

我哔哔哔,坚守树状数组的我完美WA,有时间再改,下次一定要用线段树!!!

#include<bits/stdc++.h>
using namespace std;
int n,m,i,j,tot,head[1111111],w[1111111],maxn,sum;
int dep[1111111],fa[1111111],siz[1111111],son[1111111],top[1111111],cnt,dfn[1111111],rnk[1111111],c[1111111],ssc[1111111],sscc[1111111];
char a[1111111];
struct eat{
	int ne,to;
}e[1111111];
void add(int x,int y)
{
	e[tot].to=y;
	e[tot].ne=head[x];
	head[x]=tot++;
}
int lb(int x)
{
	return -x&x;
}
void ssszsz_add(int x,int y)
{
	ssc[x]=y;
	while(x<=n)
	{
		sscc[x]=y;
		for(int j=1;j<lb(x);j<<=1)
		{
			if(sscc[x]<sscc[x-j])
			{
				sscc[x]=sscc[x-j];
			}
		}
		x+=lb(x);
	}
}
int ssszsz_qu(int x,int y)
{
	int tot=0;
	while(1)
	{
		if(tot<ssc[y]) tot=ssc[y];
		if(x==y) break;
		for(y-=1;y-x>=lb(y);y-=lb(y))
		{
			if(tot<sscc[y]) tot=sscc[y];
		}
	}
	return tot;
}
void szsz_add(int x,int y)
{
	while(x<=n)
	{
		c[x]+=y;
		x+=lb(x);
	}
}
int szsz_qu(int x)
{
	int tot=0;
	while(x>0)
	{
		tot+=c[x];
		x-=lb(x);
	}
	return tot;
}
int szsz_sum(int x,int y)
{
	return (szsz_qu(y)-szsz_qu(x-1));
}
int szsz_max(int x,int y)
{
	return ssszsz_qu(x,y);
}
void dfs1(int st)
{
	son[st]=-1;
	siz[st]=1;
	for(int i=head[st];i!=-1;i=e[i].ne)
	{
		if(dep[e[i].to]==0)
		{
			dep[e[i].to]=dep[st]+1;
			fa[e[i].to]=st;
			dfs1(e[i].to);
			siz[st]+=siz[e[i].to];
			if(son[st]==-1||siz[e[i].to]>siz[son[st]]) son[st]=e[i].to;
		}
	}
}
void dfs2(int st,int ft)
{
	top[st]=ft;
	cnt++;
	dfn[st]=cnt;
	rnk[cnt]=st;
	if(son[st]==-1) return;
	dfs2(son[st],ft);
	for(int i=head[st];i!=-1;i=e[i].ne)
	{
		if(son[st]==e[i].to||e[i].to==fa[st]) continue;
		dfs2(e[i].to,e[i].to);
	}
}
int lca(int u,int v)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]>dep[top[v]])
		{
			u=fa[top[u]];
		}
		else
		{
			v=fa[top[v]];
		}
	}
	if(dep[u]>dep[v])
	{
		return v;
	}
	else
	{
		return u;
	}
}
int pfmax(int u,int v)
{
	int ans=0;
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])
		{
			int t=u;
			u=v;
			v=t;
		}
		ans=max(ans,szsz_max(dfn[top[u]],dfn[u]));
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])
	{
		int t=u;
		u=v;
		v=t;
	}
	ans=max(ans,szsz_max(dfn[u],dfn[v]));
	return ans;
}
int pfsum(int u,int v)
{
	int ans=0;
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])
		{
			int t=u;
			u=v;
			v=t;
		}
		ans+=szsz_sum(dfn[top[u]],dfn[u]);
		u=fa[top[u]];
	}
	if(dep[u]>dep[v])
	{
		int t=u;
		u=v;
		v=t;
	}
	ans+=szsz_sum(dfn[u],dfn[v]);
	return ans;
}
int main()
{
	memset(head,-1,sizeof head);
	memset(e,-1,sizeof e);
	scanf("%d",&n);
	for(i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dep[1]=1;
	dfs1(1);
	dfs2(1,1);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&w[i]);
		szsz_add(dfn[i],w[i]);
		ssc[dfn[i]]=w[i];
		sscc[dfn[i]]=w[i];
		for(j=1;j<lb(dfn[i]);j<<=1)
		{
			if(sscc[dfn[i]]<sscc[dfn[i]-j])
			{
				sscc[dfn[i]]=sscc[dfn[i]-j];
			}
		}
	}
	scanf("%d",&m);
	for(i=1;i<=m;i++)
	{
		scanf("%s",a);
		if(a[0]=='C')
		{
			int x,y;
			scanf("%d%d",&x,&y);
			szsz_add(dfn[x],y-w[x]);
			ssszsz_add(dfn[x],y);
			w[x]=y;
		}
		else
		{
			if(a[1]=='M')
			{
				int x,y;
				scanf("%d%d",&x,&y);
				printf("%d\n",pfmax(x,y));
			}
			else
			{
				int x,y;
				scanf("%d%d",&x,&y);
				printf("%d\n",pfsum(x,y));
			}
		}
	}
}

改天用线段树再打一遍,不过我敢肯定树状数组除外的部分是对的。
哔哔哔。。。
为什么七十岁老人被恶毒夫妻推下悬崖却无人制止?为什么七个上身赤裸的男子殴打妇女却被人拍手叫好?为什么蛇蝎共处一窝却相安无事?这一切的背后,到底是道德的疏忽还是人格的泯灭亦或是社会的悲哀?如果你想了解这一切,请收看动画片《葫芦娃》!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值