heheda练数据结构

原创 2015年11月20日 22:20:37

联赛结束,自己的码力已经下降了不知多少个档次,再加上最近空闲时间比较多,我就开启了这个可以说最费时间的专题。

//话说我未完成的数论专题还会继续的。

最近看了以下知识点:

线段树套线段树

线段树套平衡树

准备学习:

替罪羊树

块状链表

复习:

树链剖分

树状数组套线段树

一些高级的线段树

可持久化tire

可并堆


bzoj 2957 楼房重建

给定第一象限的n个楼房,询问从原点能看到多少个楼房,支持修改楼房高度。

线段树维护每个点的斜率。

每个节点记录这个区间中最大的斜率,选取的个数。

修改一个点的斜率,它左面的答案是没有影响的。

对于右面,如果一个区间最大的斜率小于上一个的斜率,那么它的贡献为0.

否则,如果左区间最大值大于上一个的斜率,那么右区间答案不变,递归修改左子树。

如果小于,左区间贡献为0,递归修改右子树。

总时间复杂度nlog^2n 但是实际远远达不到。

注意:

1、右区间对当前区间的贡献不等于右区间的答案。

2、在某种情况下,double 类型的两个数是可能相等的。


bzoj 2741 L

询问区间中异或和最大的子段。 n,m 10^4 无修改,强制在线

分析:

区间是第一维数据结构,异或和最大是可持久化tire做一维数据结构。

于是,用分块维护区间答案,利用可持久化tire维护头尾答案。

预处理出每两块做左右边界的答案,暴力查询以最左面块的每个点开始的答案和以最右面块的每个点结束的答案。


bzoj 3130 k大数查询

有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

注意这不是带插入区间k大值。

学cdq的时候用一种神奇的树状数组水过。线段树套线段树的第一维不支持标记,但是第二维支持。第一维权值,第二维位置,生写即可。

第一次写下放标记的动态开点线段树,大约就是release的时候把左右儿子都建出来。

话说学cdq的时候把题刷了个遍,现在几乎找不到树套树没写过的题了。


bzoj 3196 二逼平衡树

线段树套平衡树的各项操作。每个线段树的节点是这个区间的平衡树。

第一维区间,第二维权值。

注意一开始把树建出来,而不是一个个插入。要不就卡常数了。

注意两个点权值相等的情况


bzoj 2333 棘手的操作

挖坑。

话说堆就是维护最大值的,我还维护一个变量干什么?

调了n天的代码,还是贴一下吧。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define ll long long
#define inf 1e9
#define eps 1e-10
#define md
#define N 300010
using namespace std;
int ad[N],ch[N][2],val[N],dis[N],fa[N],q[N],father[N];
multiset<int> st;
int All;
int findfa(int x) { return father[x]==x?x:father[x]=findfa(father[x]);} 
void release(int x)
{
	if (ad[x])
	{
		int l=ch[x][0],r=ch[x][1],d=ad[x];
		if (l)
		{
			ad[l]+=d; val[l]+=d;
		}
		if (r)
		{
			ad[r]+=d; val[r]+=d;
		}
		ad[x]=0;
	}
}

void update(int x)
{
	//mx[x]=val[x];
	//if (ch[x][0]) mx[x]=max(mx[x],mx[ch[x][0]]);
	//if (ch[x][1]) mx[x]=max(mx[x],mx[ch[x][1]]);
	if (dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
	dis[x]=dis[ch[x][1]]+1;
}

int merge(int x,int y)
{
	//printf("merge %d %d\n",x,y);
	if (!x) return y;
	if (!y) return x;
	if (val[x]<val[y]) swap(x,y);
	release(x);
	ch[x][1]=merge(ch[x][1],y);
	fa[ch[x][1]]=x;
	update(x);
	return x;
}

void push_down(int x)
{
	int w=0;
	while (x)
	{
		 q[++w]=x; x=fa[x];
	}
	for (int i=w;i;i--) release(q[i]);
}

void push_up(int x)
{
	while (x)
	{
		update(x);
		x=fa[x];
	}
}

int find(int x)
{
	while (fa[x]) x=fa[x];
	return x;
}

int split(int x)
{
	int f=merge(ch[x][0],ch[x][1]);
	if (fa[x]) ch[fa[x]][ ch[fa[x]][1]==x ]=f;
	fa[f]=fa[x];
	fa[x]=ch[x][0]=ch[x][1]=0;
	update(x); push_up(f);
	return find(f);
}

void addit(int x,int d)
{
	int root=find(x);
	push_down(x);
	st.erase(st.find(val[root]));
	val[x]+=d;
	root=split(x);
	root=merge(root,x); fa[root]=0;
	st.insert(val[root]);
}

void addheap(int x,int d)
{
	int root=find(x);
	st.erase(st.find(val[root]));
	ad[root]+=d; val[root]+=d; //mx[root]+=d;
	st.insert(val[root]);
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("data.in","r",stdin); freopen("data.out","w",stdout);
#endif
	int n;
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&val[i]);
		//mx[i]=val[i];
		st.insert(val[i]);
	}
	for (int i=1;i<=n;i++) father[i]=i;
	char str[5];
	int m;
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%s",str);
		//printf("st %s\n",str);
		if (str[0]=='U')
		{
			int x,y;
			scanf("%d%d",&x,&y);
			push_down(x); push_down(y);
			int f1=findfa(x),f2=findfa(y);
			if (f1==f2) continue;
			father[f1]=f2;
			f1=find(x); f2=find(y);
			st.erase(st.find(val[f1])); st.erase(st.find(val[f2]));
			f1=merge(f1,f2); fa[f1]=0;
			st.insert(val[f1]);
		}
		else if (str[0]=='A')
		{
			int x,d;
			if (str[1]=='1')
			{
				scanf("%d%d",&x,&d);
				addit(x,d);
			}
			else if (str[1]=='2')
			{
				scanf("%d%d",&x,&d);
				addheap(x,d);
			}
			else //if (str[1]=='3')
			{
				scanf("%d",&d);
				All+=d;
				//printf("all %d %d\n",d,All);
			}
			//else printf("? %s\n",str);
		}
		else
		{
			int x;
			if (str[1]=='1')
			{
				scanf("%d",&x);
				push_down(x);
				printf("%d\n",val[x]+All);
			}
			else if (str[1]=='2')
			{
				scanf("%d",&x);
				printf("%d\n",val[find(x)]+All);
			}
			else
			{
				int a=*--st.end(); //printf("a %d\n",a);
				printf("%d\n",a+All);
			}
		}
	}
}


bzoj 4009 接水果

挖坑。


bzoj 4336 骑士的旅行

挖坑,已经尝试了权值线段树套平衡树和线段数套线段树,都过不了,改天有心情写一个常数20的线段树,或许能过?


11.28更

这个周主要做了各个数据结构的一些裸题。

bzoj 1146 骑士的旅行 线段树套平衡树+树链剖分+线段树上二分。

bzoj 2733 永无乡

开始想要 splay+启发式合并,感觉有点虚,就看了hzwer的线段树合并,感觉好扯,但是,细想想,复杂度是有保证的。

需要merge的线段树节点一定是两颗线段树共有的,那么一定少于小的线段树的节点数,所以小线段树的size就扩大了2倍,最多扩大log次,也就是启发式合并的复杂度分析。


bzoj 4012 开店

这是我这个周唯一写的不是太裸的题了吧。



蒟蒻的noip2015滚粗记

oi就是一场实力与运气的博弈——题记        也不知道这会不会是自己的最后一年noip,也不知道2016夏绵阳见是什么样子。但是,第三年的noip,还是值得回味的。 Day 0      ...

SDOI2016r1游记

做梦一般,SDOIR1就过去了,成绩不错,但总有一些小的细节不是太如意。 Day0 早上10点的火车,在车上和同学聊了一些奇奇怪怪的题,就到了济南,然后报道。感觉自己整个人都hai起来了。晚上写了...

两周年纪念

转眼就两年了…… 两年前想进省队,没进 一年前想拿金牌,没拿 现在想高考…… 我才不会立奇怪的flag,口亨...

java语言程序设计(进阶篇)读书笔记 之 数据结构每天一小练--堆(一)

堆是一种特殊的完全二叉树,它要求每个节点都大于或等于它的一个子节点 由于二叉树的性质可知 1,一个节点的父节点(i)的位置在:(i-1) / 2 2,一个节点的坐子节点(i)的位置为...

一天一练数据结构之-直接插入算法

直接插入算法: 相信有一点算法经验的人都会知道这个算法,比较简单,今天就拿这个来练练手。 下面说下算法的思路: 给定一个数组,0号单元存放数组中实际存放的数据长度。 进行排序的过程为: 如果...

程序设计与数据结构.周立功单片机

  • 2017年12月08日 13:55
  • 25.85MB
  • 下载

数据结构C++单链表冒泡法排序

  • 2017年12月06日 14:22
  • 2KB
  • 下载

第十四讲 适配器模式、内部类、递归算法、数据结构之链表、包装类、Eclipse开发环境设置

导读 适配器模式,也是Java二十三中设计模式之一。让其他的对象可以适应规范,其实这样说是不是觉得很迷糊啊? 我们把适配器模式当做我们家电用的插座,对,就是这样来想就很容易学习和应用了。 内...

数据结构习题集

  • 2017年12月06日 17:20
  • 293KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:heheda练数据结构
举报原因:
原因补充:

(最多只允许输入30个字)