heheda练数据结构

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

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

最近看了以下知识点:

线段树套线段树

线段树套平衡树

准备学习:

替罪羊树

块状链表

复习:

树链剖分

树状数组套线段树

一些高级的线段树

可持久化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 开店

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



你可能感兴趣的:(数据结构)