MRaZY MRain is CraZY! This is old CodeBeta.

8六/100

万能的Splay-处理区间问题

为什么会用到Splay呢,Splay虽然很强大但是不)同问题上替代品也有不少。其实主要是最近看到动态树、Link-cut Tree,里面需要维护一条路径的信息,而且路劲还是可分割,可合并的,这里Splay就是最佳的组件了。

Splay如果仅仅作为一棵二叉平衡查找树(BST)来使用的话的确效率是不尽人意,不过正如Splay的中文名—伸展树,它的发明不仅仅是作为一棵平庸的BST来使用的,较高的常数和看起来不怎么爽的平摊O(logN)的效率带来的是其非常丰富的功能。比如现在所讲的—如何用Splay处理区间问题。

给个例题,POJ3468,题目意思是:给一个连续的区间[1..N],区间里每个元素上面都有一个数值。每次有两种询问,第一种是给定区间[A,B],把里面所有元素的数值加上某个数字C,第二种询问是给定区间[A,B],求区间里所有元素数值的和。

其实这题用线段树还是能非常轻松的过掉的。不过今天就要自虐一下写个Splay。

首先呢,我们以元素的序号为关键字建一个二叉查找树(平衡不平衡这里其实无所谓,反正Splay几下就均摊平衡了。),树上的每个节点代表一个元素,为了方便起见我们可以再插入两个元素0和N+1(等下你就知道为什么需要这俩东西了。)。

接下来的问题呢,是如何把一段连续的区间在树上展现出来,一般人都会比较混沌,因为树上的结构看起来或许很乱。但是Splay在这里就发挥了他十分大的优势,比如,询问区间为[A,B],我们可以先把元素A-1旋到树根,这样询问区间里的所有元素都在树根的右子树里,接下来的手法类似,就是单独取下那棵右子树([0..A-1]区间里的元素就这样被我们忽略了),然后把B+1选到树根上,这样树根的左子树就是代表着我们需要处理的区间[A,B]了。

接下来的事情就比较简单了,对于第一种询问,我们可以对于每个节点多记录下一个新信息size,表示以该节点为根的子树下有多少个节点,然后再用类似线段树的标记传递的方法覆盖下去。对于第二种询问,我们可以对每个节点维护sum,表示以该节点为根的子树下所有元素的和是多少。然后问题就此解决了哈哈~

(Splay的基础知识参考NOI WinterCamp2004杨思雨的论文)

标签: , , , 继续阅读
26五/091

NetworkFlow.Dinic Let's do it.

网络流算法有许多种,最基本的一种方法是Fold-Fulkerson.不过裸奔的Fold-Fulkerson的效率总是不尽如人意.于是各种优化层出不穷.

比较牛X的一个就是基于分层图思想的MPLA(最短路径增值).在层次图里,从源点开始,不管怎么走,总能走到汇点,而且保证是最短路.这是一个非常优美的性质.复杂度证明...找WC2007王欣上论文吧..

于是便有了以下的裸的MPLA程序(附件1).每次计算出一个层次图.然后进行若干次DFS寻找增广路.

Dinic是基于MPLA上的另外一个改进.引入一个新的名词叫做块流,表示在一张剩余图上所有可增广的流量.Dinic在每次计算出层次图后,仅用一次DFS来找出这张图的块流,避免了许多废的搜索状态和回溯状态.详见程序(附件2).

13四/093

Win7 7106 简体中文版简要评测报告

昨晚作为第一波下完的(9点左右才下好),赶紧给装上.

采用的是F8的修复计算机安装(我原本用的还是Win7 7000 beta),安装的速度快的惊人啊.

总共只花了十五分钟左右..在我这台07年的本本上.

新装的系统速度快了很多.中文版的..开机的"Starting Windows"变成了"正在启动Windows"

以及..Windows 7 Ultimate变成了Windows 7 旗舰版(这个还是有点儿囧..)

先上截图..

4四/090

在Ural上被阴了一题 -> Ural 1028

题目就不多说了..原本是找些线段树的题目来练练手.

结果这题..看起来好水..可以用树状数组切掉..

看到这么水的题目不忍心放弃..就开始随便写..

结果交上去TLE..觉得非常新奇..找了段线段树的程序扔上去AC了.(没天理啊..)

仔细观察题目.才发现..当坐标为0的时候..我可怜的树状数组啊..就开始无限的循环下去了.

还好..赶紧解决..可以把所有坐标加个1..也可以对于0的情况特判.

以下为我AC的程序:

#include <stdio.h>
#include <memory.h>
 
int n,a[15001],b[15001],ans[15001],tree[60000],t;
 
int Query(int a)
{
	if (!a)
		return tree[0];
	int ans = 0;
	while (a)
	{
		ans += tree[a];
		a -= (a & (-a));
	}
	return ans + tree[0];
}
 
void update(int a)
{
	if (!a) { ++ tree[0]; return; }
	while (a <= 32768)
	{
		++ tree[a];
		a += (a & (-a));
	}
}
 
int main()
{
	freopen("input.txt","r",stdin);
	scanf("%d",&n);
	for (int i=1; i<=n; ++i)
		scanf("%d %d",&a[i],&b[i]);
	for (int i=1; i<=n; ++i)
	{
		update(a[i]);
		t = Query(a[i]);
		++ ans[t];
	}
	for (int i=1; i<=n; ++i)
		printf("%d\n",ans[i]);
}
11三/091

POJ 3719 Art of Balance

PKU某月的月赛中的一道题.写一写来练手.

题目大意是: 给出m个砝码(m<=16),有一个有n个节点的二叉树(n<=100),这棵树上有m个叶子节点,每个叶子节点可以挂上一颗砝码,一颗子树的重量是地下挂的所有砝码的重量之和,定义不平衡量为abs((lch.weight / root.weight)-1/2)*1000 , 要求给出一种方案,是的不平衡量的总和最小.

稍微想了下..m只有16..好吧...状态压缩的treedp.

记下f[root,state]为处理根为root的子树,底下用的砝码的状态为state..然后直接转移吧..

#include <stdio.h>
#include <memory.h>
 
typedef struct treenode{
	int lch,rch,count;
};
 
int cases,n,m,a[17],st[17][65538];
double f[102][65538],w[65538];
struct treenode tree[102];
 
int dfs(int root)             //统计每棵子树所包含的叶子节点的数目.
{
	if (tree[root].lch < 0 && tree[root].rch < 0) tree[root].count = 1;
	else tree[root].count += dfs(tree[root].lch) + dfs(tree[root].rch);
	return tree[root].count;
}
 
void calc_w()                //计算各种状态的重量
{
	memset(w,0,sizeof(w));
	for (int i=1; i<(1 << m); ++i)
		for (int j=0; j<m; ++j)
			if (i & (1 << j))
				w[i] += a[j+1];
}
 
void build_state(int state,int posi,int len)  //生成有用状态
{
	if (posi > 16) return;
	build_state(state,posi+1,len);
	state = state | (1 << (posi-1));
	st[++len][++st[len][0]] = state;
	build_state(state,posi+1,len);
}
 
double abs(double a)
{
	if (a < 0)
		a = -a;
	return a;
}
 
double search(int root,int state)           //DP主过程.(记忆化搜索)
{
	if (f[root][state] < 0)
	{
		f[root][state] = 2000000000;
		if (tree[root].count == 1)
		{
			f[root][state] = 0;
			return 0;
		}
		for (int i=1; i<=st[tree[tree[root].lch].count][0]; ++i)
		{
			int tstate = st[tree[tree[root].lch].count][i];
			if ((state & tstate) == tstate)
			{
				double temp = search(tree[root].lch,tstate)+search(tree[root].rch,state ^ tstate)+abs((w[tstate]/w[state])-0.5)*1000;
				if (f[root][state] > temp)
					f[root][state] = temp;
			}
		}
	}
	return f[root][state];
}
 
int main()
{
	scanf("%d",&cases);
	build_state(0,1,0);
	for (; cases; --cases)
	{
		scanf("%d",&n);
		memset(tree,0,sizeof(tree));
		for (int i=1; i<=n; ++i) scanf("%d %d",&tree[i].lch,&tree[i].rch);
		dfs(1);
		scanf("%d",&m);
		memset(a,0,sizeof(a));
		for (int i=1; i<=m; ++i) scanf("%d",&a[i]);
		calc_w();
		for (int i=1; i<=n; ++i)
			for (int j=1; j<(1 << m); ++j)
				f[i][j] = -1.0;
		printf("%.3lf\n",search(1,(1 << m)-1));
	}
}
标签: , , 1个评论
Page 1 of 512345