【树链剖分】【dfs序】【线段树】bzoj2836 魔法树

这道题告诉我们:树链剖分的重标号就是dfs序。

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 100001
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
typedef long long ll;
ll delta[N<<2],sumv[N<<2];
int n,m;
int en,v[N],first[N],next[N];
void AddEdge(const int &U,const int &V)
{
	v[++en]=V;
	next[en]=first[U];
	first[U]=en;
}
int dep[N],fa[N],siz[N],son[N],tot,Ls[N],top[N],Rs[N];
void dfs(int U)
{
	siz[U]=1;
	for(int i=first[U];i;i=next[i])
	  {
	  	fa[v[i]]=U;
	  	dep[v[i]]=dep[U]+1;
	  	dfs(v[i]);
	  	siz[U]+=siz[v[i]];
	  	if(siz[son[U]]<siz[v[i]])
	  	  son[U]=v[i];
	  }
}
void dfs2(int U)
{
	Ls[U]=++tot;
	if(son[U])
	  {
	  	top[son[U]]=top[U];
	  	dfs2(son[U]);
	  }
	for(int i=first[U];i;i=next[i])
	  if(v[i]!=son[U])
	    {
	      top[v[i]]=v[i];
	      dfs2(v[i]);
	    }
	Rs[U]=tot;
}
void pushdown(int rt,int size)
{
	if(delta[rt])
	  {
		delta[rt<<1]+=delta[rt];
		delta[rt<<1|1]+=delta[rt];
		sumv[rt<<1]+=delta[rt]*(ll)(size-(size>>1));
		sumv[rt<<1|1]+=delta[rt]*(ll)(size>>1);
		delta[rt]=0;
	  }
}
void update(int ql,int qr,int v,int rt,int l,int r)
{
	if(ql<=l&&r<=qr)
	  {
	  	delta[rt]+=(ll)v;
	  	sumv[rt]+=((ll)(r-l+1)*(ll)v);
	  	return;
	  }
	pushdown(rt,r-l+1);
	int m=(l+r>>1);
	if(ql<=m) update(ql,qr,v,lson);
	if(m<qr) update(ql,qr,v,rson);
	sumv[rt]=sumv[rt<<1]+sumv[rt<<1|1];
}
ll query(int ql,int qr,int rt,int l,int r)
{
	if(ql<=l&&r<=qr) return sumv[rt];
	pushdown(rt,r-l+1);
	int m=(l+r>>1); ll res=0;
	if(ql<=m) res+=query(ql,qr,lson);
	if(m<qr) res+=query(ql,qr,rson);
	return res;
}
void Update(int U,int V,int W)
{
	int f1=top[U],f2=top[V];
	while(f1!=f2)
	  {
	  	if(dep[f1]<dep[f2])
	  	  {
	  	  	swap(U,V);
	  	  	swap(f1,f2);
	  	  }
	  	update(Ls[f1],Ls[U],W,1,1,n);
	  	U=fa[f1];
	  	f1=top[U];
	  }
	if(dep[U]>dep[V])
	  swap(U,V);
	update(Ls[U],Ls[V],W,1,1,n);
}
int main()
{
	int A,B,C; char op[2];
	scanf("%d",&n);
	for(int i=1;i<n;++i)
	  {
	  	scanf("%d%d",&A,&B);
	  	AddEdge(A+1,B+1);
	  }
	top[1]=1;
	dfs(1);
	dfs2(1);
	scanf("%d",&m);
	for(;m;--m)
	  {
	  	scanf("%s%d",op,&A);
	  	if(op[0]==‘A‘)
	  	  {
	  	  	scanf("%d%d",&B,&C);
	  	  	Update(A+1,B+1,C);
	  	  }
	  	else
		  printf("%lld\n",query(Ls[A+1],Rs[A+1],1,1,n));
	  }
	return 0;
}
时间: 2024-10-21 21:33:00

【树链剖分】【dfs序】【线段树】bzoj2836 魔法树的相关文章

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

题目链接 这道题主要是要考虑到同一棵子树中dfs序是连续的 然后我就直接上树剖了... 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=600005; 4 5 struct Node 6 { 7 int l,r; 8 int value; 9 void init() 10 { 11 l=r=value=0; 12 } 13 }tree[4*MAXN]; 14 vector<int>nei[MAXN]

BZOJ 2819 Nim 树链剖分/DFS序+LCA+树状数组

题意:给定一棵树,每个节点是一堆石子,给定两种操作: 1.改变x号节点的石子数量 2.用从x到y的路径上的所有堆石子玩一次Nim游戏,询问是否有必胜策略 Nim游戏有必胜策略的充要条件是所有堆的石子数异或起来不为零 这题首先一看就是树链剖分 然后题目很善良地告诉我们深搜会爆栈 于是我们可以选择广搜版的树链剖分 BFS序从左到右是深搜,从右到左是回溯,一遍BFS就够 单点修改区间查询还可以套用ZKW线段树 不过这题其实不用这么麻烦 有更简单的办法 详见 http://dzy493941464.is

BZOJ 2286 树链剖分+DFS序+虚树+树形DP

第一次学习虚树,就是把无关的点去掉.S里维护一条链即可. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #define LL long long 6 using namespace std; 7 const LL Maxm=501000; 8 const LL Maxn=250100; 9 const LL Inf=1e60; 1

BZOJ 2243:染色(树链剖分+区间合并线段树)

[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”.请你写一个程序依次完成这m个操作.Input第一行包含2个整数n和m,分别表示节点数和操作数:第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边.下面 行每行描述一个操作:“C

BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2243 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写

【BZOJ4515】游戏,树链剖分+永久化标记线段树维护线段信息(李超线段树)

Time:2016.05.10 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 李超线段树 一开始听faebdc讲,并没有听的很懂ww 后来找到良心博文啊有木有 折越 首先可以把修改转换一下,因为那个dis非常不爽.显然s~t的路径有s~lca和lca~t组成.令d[x]表示x的深度,对于s~lca上面的点,修改的值相当于a*(d[s]-d[x])+b=-a*d[x]+(b-a*d[s]),lca~t上面的点的值相当于a*(d[s]+d[x]-2*d[lca])+b=a*d[x

【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\),问你答案是多少. \(n\leq {10}^5,k\leq {10}^9\) 题解 设\(l\)为这棵树的叶子个数,显然当\(k>\)树的深度时答案都是\(l\). 下面要证明:答案是\(O(l+\frac{n-l}{k})\)的. 我们从下往上贪心,每次选择一个未被覆盖的深度最深的点,覆盖这个点网

【块状树】【树链剖分】【线段树】bzoj3531 [Sdoi2014]旅行

离线后以宗教为第一关键字,操作时间为第二关键字排序. <法一>块状树,线下ac,线上tle…… #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> using namespace std; queue<int>q; int f,c; inline void R(int &x){ c=0;f=1;

【树链剖分(区间线段树)】BZOJ4196-[NOI2015]软件包管理

[题目大意] 如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B.同时,如果想要卸载软件包B,则必须卸载软件包A.而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包.依赖关系不存在环.求出在安装和卸载某个软件包时,实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包.(注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安

【树链剖分】【线段树】bzoj3626 [LNOI2014]LCA

引用题解: http://blog.csdn.net/popoqqq/article/details/38823457 题目大意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)].(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和) 这题看见了直接卡壳...然后