微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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 <iostream>
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,sizeof(add));
	memset(sum,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 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<R) updateSegment(L,rson);
	PushUp(rt);
}

LL querySum(int L,int rt)//线段树区间求和,不过这个不是树链剖分的区间求和
{
	if (L <= l && r <= R) 
	{
		return sum[rt];
	}
	PushDown(rt,r - l + 1);
	int m = (l + r) >> 1;
	LL ret = 0;
	if (L<=m) ret += querySum(L,lson);
	if (m<R) ret += querySum(L,rson);
	return ret;
}

void init(int n)//所有初始化
{
	eroot = (n + 1) / 2;
	fa[eroot] = tct = dep[eroot] = 0;
	memset(siz,sizeof(siz));
	dfs1(eroot);
	dfs2(eroot,eroot);
	buildSegment(1,tct,1);//建立空的线段树
	int i;
	for (i=1; i<=n; i++)//把初始的权值更新到线段树上
	{
		updateSegment(w[i],w[i],enemy[i],1,1);
	}
}
void update(int va,int vb,int c)//树链剖分的更新
{
	int f1 = top[va],f2 = top[vb];
	while(f1!=f2)
	{
		if (dep[f1]<dep[f2])
		{
			swap(f1,f2);
			swap(va,vb);
		}
		updateSegment(w[f1],w[va],1);
		va = fa[f1];
		f1 = top[va];
	}
//	if (va==vb) return;//因为这道题是以点位权的,所以点需要更新
	if (dep[va]>dep[vb])
	{
		swap(va,vb);
	}
	updateSegment(w[va],w[vb],1);
}

int main()
{
	int n,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<n; i++)
		{
			scanf("%d %d",&x,&y);
			insertEdge(x,0);
			insertEdge(y,x,0);
		}
		init(n);
		for (i=0; i<p; i++)
		{
			scanf("%s",cmd);
			if (cmd[0]=='I')
			{
				scanf("%d %d %d",&y,&z);
				update(x,z);
			}
			else if (cmd[0]=='D')
			{
				scanf("%d %d %d",-z);
			}
			else
			{
				scanf("%d",&x);
				printf("%d\n",querySum(w[x],w[x],1));
			}			
		}
	}
    return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr