HDU3966 Aragorn's Story 树链剖分

Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=3966


【前言】


前几天在学树链剖分。主要还是为比赛做一下模板。但是找不到很基础的题可以做。

这道题的线段树部分不是最简单的那种,用的也是别人的模板。

上次WA了,好几天还没碰。

但是今天早上起来看了一下,就改了一个地方,然后就过了。

看来应了那句话:把最困难的任务放在早上做。


【思路】


简单说下树链剖分。

树链剖分的应用就是动态地修改一棵树上的边权,同时动态地查询每两个节点之间路径上的信息,包括最值、和等。

树链剖分就是把一棵树从上到下划分为一条条链,这样做的好处是更新或查询的时候可以成段地进行。

详细请看:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html

网上代码很多,讲解的很少。上面这篇文章我觉得里面讲的很详细,例子给的也很到位。

当看懂之后发现,更新或查询的时候就是使用线段树了!

线段树的应用包括求最值、和等。也包括成段的更新和查询。


【代码】


树链剖分和线段树代码都是用的别人的,不过其实树链剖分没有想象中的那么困难。


#include 
using namespace std;

const int maxn = 50010;

struct edgeNode
{
	int value;
	int to;
	int next; 
}edge[maxn*2];
int ect;
int ehead[maxn];
int eroot;

int tct;

int dep[maxn], w[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn];

void initEdge(int n)//树的初始化
{
	ect = 0;
	eroot = 1;
	int i;
	for (i=0; i<=n; i++) ehead[i] = -1;
}

void insertEdge(int from, int to, int value)//插入一条树的边
{
	edge[ect].to = to;
	edge[ect].value = value;
	edge[ect].next = ehead[from];
	ehead[from] = ect;
	ect++;
}

void dfs1(int v)//第一层搜索
{
     siz[v] = 1; 
	 son[v] = 0;
	 int i;
     for (i=ehead[v]; i+1!=0; i=edge[i].next)
	 {
         if (edge[i].to!=fa[v])
         {
             fa[edge[i].to] = v;
             dep[edge[i].to] = dep[v]+1;
             dfs1(edge[i].to);
             if (siz[edge[i].to]>siz[son[v]]) son[v]=edge[i].to;
             siz[v] += siz[edge[i].to];
         }
	 }
}

void dfs2(int v, int tp)//第二层搜索,获得每个节点在线段树中的位置
{
	tct++;
	w[v] = tct;
	top[v] = tp;
	if (son[v]!=0) dfs2(son[v], top[v]);
	int i;
	for (i=ehead[v]; i+1!=0; i=edge[i].next)
	{
		if (edge[i].to!=son[v] && edge[i].to!=fa[v])
			dfs2(edge[i].to, edge[i].to);
	}
}

int enemy[maxn];
//以下为线段树部分
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define LL int

LL add[maxn<<2];
LL sum[maxn<<2];

void PushUp(int rt) 
{
	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void PushDown(int rt,int m) 
{
	if (add[rt]) {
		add[rt<<1] += add[rt];
		add[rt<<1|1] += add[rt];
		sum[rt<<1] += add[rt] * (m - (m >> 1));
		sum[rt<<1|1] += add[rt] * (m >> 1);
		add[rt] = 0;
	}
}

void buildSegment(int l, int r, int rt) //建立线段树,可以直接全部初始化为0
{
	memset(add, 0, sizeof(add));
	memset(sum, 0, sizeof(sum));
	/*
	add[rt] = 0;
	if (l==r)
	{
		sum[rt] = 0;
		return;
	}
	int m = (l + r) >> 1;
	buildSegment(lson);
	buildSegment(rson);
	PushUp(rt);*/
}

void updateSegment(int L, int R, int c, int l, int r, int rt)//线段树区间更新
{
	if (L<=l && r<=R) 
	{
		add[rt] += c;
		sum[rt] += (LL)c * (r - l + 1);
		return;
	}
	PushDown(rt , r - l + 1);
	int m = (l + r) >> 1;
	if (L<=m) updateSegment(L, R, c, lson);
	if (m> 1;
	LL ret = 0;
	if (L<=m) ret += querySum(L, R, lson);
	if (mdep[vb])
	{
		swap(va, vb);
	}
	updateSegment(w[va], w[vb], c, 1, tct, 1);
}

int main()
{
	int n, m, p;
	int i;
	int x, y, z;
	char cmd[5];
	while(scanf("%d %d %d", &n, &m, &p)!=EOF)
	{
		for (i=1; i<=n; i++) scanf("%d", &enemy[i]);
		initEdge(n);
		for (i=1; i


你可能感兴趣的:(数据结构)