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