【专题】树

(update:2012.11.22)


【这绝对是个坑啊!!!】

资料:http://pan.baidu.com/share/link?shareid=116174&uk=3491581918

1.  基础知识

a)        树状数组、线段树、堆、可并堆、Trie

b)       平衡树(splay、treap/sbt)

c)        LCA、RMQ、LCT、树链剖分

2.  树上的修改、询问

a)        修改点权,问路径上的点权和、子树点权和

b)       修改路径上的点(每个点点权同时加减定制),询问子树点权和、单点点权

c)        修改子树点权(每个点点权同时加减定制),询问路径点权和,单点点权

d)       修改子树点权(每个点点权同时加减定制),询问子树点权和

e)        将路径上所有点点权设置为w,查询路径上边权组成的序列的最大子段和

f)         Qtree系列

       i.   修改边权问路径上最大边,n<=10^4.

      ii.   问路径上的k短边,n<=10^4.

     iii.   (1)对一棵被黑白染色的树,支持对于某个节点反色、查询节点1 到i路径上第一个黑色节点的编号。

            (2)给定一棵有根树,树根为1,询问某子树中k大权值的节点是哪个,

            (1)、(2)范围均为n、q<=10^5

     iv.   对一棵被黑白染色的树,支持对于某个节点反色、查询数中最远的两个白色节点的距离。n、q<=10^5

      v.   对一棵被黑白染色的树,初始时所有节点均为黑色,要求支持对于某个节点反色、查询节点1 到i路径上第一个黑色节点的编号。查询距离i最远的白色节点的编号。

    n、q<=10^5

附 :Qtree Links:

1.   http://www.spoj.pl/problems/QTREE/

2.   http://www.spoj.pl/problems/QTREE2/

3.1 http://www.spoj.pl/problems/QTREE3/

3.2 https://www.spoj.pl/problems/PT07J/

4.   http://www.spoj.pl/problems/QTREE4/

5.   http://www.spoj.pl/problems/QTREE5/

3.  树形DP

a)       树形依赖背包、泛化物品  详见背包九讲。

b)       LJQ树的难题、DP合集、分类练习题、自己找题。

c)       Trie、ACAutomatic 上的DP

4.  生成树

a)       基础算法

b)       次小、最优比例(01分数规划)、度限制、生成树计数(生成树的计数及其应用(ZD))


5.  Link-Cut Tree介绍  

其实我也是最近才开始看......

这个东西真是让人欢喜让人忧...欢喜在于这东西真是太好用了..忧在于总是难以弄清细节..至今都不是很懂。

实际上LCT还是蛮好写的。只是常数嘛...不过据说可以用全局平衡二叉树来优化。但是又是一段代码。

具体的可以看杨哲的论文和FHQ的博客。论文在资料中。

弹飞绵羊的code:(只会最基础的求破...)

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<windows.h>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<climits>
#define isr(x) ((x) -> f -> c[1] == (x))
#define isl(x) ((x) -> f -> c[0] == (x))
#define setc(F,d,C) (((F) -> c[d] = (C)) -> f = (F))
#define maxm 200010
#define maxn 200005
#define ot "%d"
#define kh "\n"
#define top(x) ((x) -> f == null || ((x) != (x) -> f -> c[0] && (x) != (x) -> f -> c[1]))

using namespace std;

struct node {int s; node *c[2], *f;} *null, *a[maxn], *head, *tail, vess[maxm];
typedef node *NODE;

int pop = maxn - 1, n, q, x, y;

void prepare()
{
	null = &vess[maxm - 1], null -> s = 0, null -> f = null;
	for (int i = 0; i < maxn; ++i) a[i] = &vess[i], vess[i] = (node){1, {null, null}, null};
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
}

NODE update(NODE x)
{
	if (x == null) return null;
	x -> s = x -> c[0] -> s + x -> c[1] -> s + 1;
	return x;
}

void rotate(NODE x)
{
	NODE y = x -> f, z = y -> f; bool k = isl(x);
	if (x -> c[k] != null)
		setc(y, !k, x -> c[k]);
	else
		y -> c[!k] = null;
	if (isl(y)) z -> c[0] = x;
	if (isr(y)) z -> c[1] = x;
	x -> f = z;	setc(x, k, update(y));
}

NODE splay(NODE x)
{
	for (; !top(x); rotate(x))
		if (!top(x -> f))
			rotate((isr(x) ^ isr(x -> f)) ? x : x -> f);
	return update(x);
}

NODE access(NODE x)
{
	NODE y = null;
	while (x != null)
		splay(x) -> c[1] = y, y = update(x), x = x -> f;
	return y;
}

int main()
{
	prepare();
	scanf(ot, &n);
	int k;
	for (int i = 0; i < n; ++i)
	{
		scanf(ot, &k);
		a[i] -> f = a[i + k > n ? n : i + k];
	}
	for (scanf(ot, &q); q; --q)
	{
		scanf(ot, &k);
		if (k == 1) scanf(ot, &x), printf(ot kh, access(a[x]) -> s - 1);
		else
		{
			scanf(ot ot, &x, &y);
			splay(a[x]) -> c[0] -> f = a[x] -> f, a[x] -> c[0] = null;
			update(a[x]) -> f = a[x + y > n ? n : x + y];
		}
	}
	return 0;
}

6.  Solution For 2

a)        修改点权,问路径上的点权和、子树点权和

            i.     询问子树的点权和:

我们通过DFS序转化为区间求和即可。树状数组或线段树实现

            ii     询问路径上的点权和

转化为点事件。在DFS序中,X为根的子树是一段区间[L, R], 我们将D[L]加上改变值,将D[R + 1]减去改变值,再次转化为区间求和。

b)       修改路径上的点(每个点点权同时加减定制),询问子树点权和、单点点权

             i.     询问单点点权:转化为单点修改、查询子树和。

             ii     询问子树点权和:转化为单点修改、查询路径和。考察贡献,变量分离,树状数组维护。首先把修改等价转化为修改X到1的路径上所有点的权值。然后同样考虑修改X对查询Y的贡献。显然当X在Y的子树内时候才会产生贡献,且贡献为W ( X ) * ( depth[ X] - depth [ Y ] + 1 ),分离变量得W ( X ) * ( depth[ X ] + 1 ) - W ( X ) * depth [ Y ]。前一项与Y无关,于是转化为问题2,可以用一个树状数组维护,后一项里W(X)与Y无关,也转化为问题2,用一个树状数组维护,有了W ( X ) * ( depth [ X ] + 1 )和W(X)我们就可以计算出询问的答案。

c)        修改子树点权(每个点点权同时加减定制),询问路径点权和,单点点权

        i.     询问单点点权。点事件。

        ii.    询问路径。LCT或变量分离。

d)       修改子树点权(每个点点权同时加减定制),询问子树点权和。点事件。

e)        将路径上所有点点权设置为w,查询路径上边权组成的序列的最大子段和


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值