[HAOI2013] 软件安装

Posted qjs12

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2013] 软件安装相关的知识,希望对你有一定的参考价值。

  这道题目在做的时候是一道让我比较头疼的题目,记得那时候总是整理完思路而不想写程序,很多次刚开始写觉得麻烦就又放弃了。不过那天下午还是逼着自己怎么也要把这题做了。

  题目要求长度大于k的最靠左的一段连续空白。

  线段树应该是人人都能想到的解决这道题的数据结构。

  接下来我们应当考虑怎么分,这么合。

  先考虑分。(假设合法解存在)

  查询函数。

  1:左区间的最大连续空白大于等 k ,递归到左子树。

  2:左区间靠右一部分与右区间靠左一部分的连续空白满足条件,直接对该区间进行长度为k的覆盖。

  3:递归到右子树进行。

  按照上述方式,每次覆盖操作一定在步骤二进行,也就是说,我将步骤二视为递归边界,且查询到合法区间后,我接着用另一个函数进行覆盖操作。

  覆盖函数。

  就像普通的区间覆盖一样,因为只要找到了正确的区间,覆盖操作的难度就跟删除操作一样了,打上标记就OK了。

  这道题目的另一个难点在于合。

  为了正确的得到最大连续空白,我在线段树节点中保存了如下变量:

  l:区间左端点。

  r:区间右端点。

  left:  区间由左端点向右延伸的最大空白。

  right:区间由右端点向左延伸的最大空白。

  fix:左子树right+右子树left的值。

  maxx:区间最大空白。

  lazy:区间是否被完全覆盖(1)或完全空白(2)。

  有了这些变量,只要写好update(),这道题就会顺利解决了。

  其实也并不难写。

  l,r 在建树时直接得到且不会改变。

  left:由左子区间的 left 值更新,且在此要考虑左右区间合并的问题,如果 lc->l + lc->left == rc->l ,也就是说左子区间完全空白,那么当前区间的 left 要加上右子区间的 left,才能得到正确的值。

  right: 由右子区间的 right 值更新,同样考虑区间合并,如果 rc->r - rc->right == lc->r ,说明右子区间完全空白,那么当前区间的 right 要加上左子区间的 right,这两个操作是对称的。

  fix:这个简单,直接 lc->right + rc->left ,即可。

  maxx:取左子区间 maxx,右子区间maxx,当前区间 fix 三者中较大的一个。

  lazy:覆盖时打标记1,清空时打标记2。

  update()顺利完成,就是有些繁琐但是很好理解。

  接下来只剩一个pushdown()。

  因为pushdown()在区间完全覆盖或完全空白时下传调用,因此很好写,只需要把子区间更新为完全覆盖或完全空白并打上标记,清空自己的标记即可,常规操作。

  至此,这道题就顺利解决了。

  PS:写题的时候没注意,不过写题解时我发现我的覆盖操作复杂度好像是 O ( log2 ) 的,因为我先查询对应区间后进行覆盖。

 

// q.c

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int M=50000+10;
int n,m;
struct Node {
	int l,r,left,right,fix,maxx,lazy;
	Node():l(0),r(-1),left(0),right(0),fix(0),maxx(0),lazy(0) {}
};
struct SegmentTree {
	int root;
	Node nd[M<<2];
	SegmentTree():root(1) {}
	void update(int o) {
		Node &p=nd[o],&lc=nd[o<<1],&rc=nd[o<<1^1];
		p.left=lc.left; if(lc.l+lc.left==rc.l) p.left+=rc.left;
		p.right=rc.right; if(rc.r-rc.right==lc.r) p.right+=lc.right;
		p.fix=lc.right+rc.left;
		p.maxx=max(lc.maxx,rc.maxx);
		p.maxx=max(p.maxx,p.fix);
	}
	void pushdown(int o) {
		Node &p=nd[o],&lc=nd[o<<1],&rc=nd[o<<1^1];
		if(p.lazy==1) {
			lc.left=lc.right=lc.fix=lc.maxx=0;
			rc.left=rc.right=rc.fix=rc.maxx=0;
			lc.lazy=rc.lazy=1; p.lazy=0;
		} else if(p.lazy==2) {
			lc.left=lc.right=lc.fix=lc.maxx=lc.r-lc.l+1;
			rc.left=rc.right=rc.fix=rc.maxx=rc.r-rc.l+1;
			lc.lazy=rc.lazy=2; p.lazy=0;
		}
	}
	void build(int o,int l,int r) {
		nd[o].l=l,nd[o].r=r;
		if(l==r) nd[o].left=nd[o].right=nd[o].fix=nd[o].maxx=1;
		else {
			int mid=(l+r)>>1;
			build(o<<1,l,mid);
			build(o<<1^1,mid+1,r);
			update(o);
		}
	}
	void solve(int o,int l,int r,int x) {
		Node &p=nd[o];
		if(l<=p.l&&p.r<=r) {
			if(x) p.left=p.right=p.fix=p.maxx=0,p.lazy=1;
			else p.left=p.right=p.fix=p.maxx=p.r-p.l+1,p.lazy=2;
		} else {
			pushdown(o);
			int mid=(p.l+p.r)>>1;
			if(l<=mid) solve(o<<1,l,r,x);
			if(r>mid) solve(o<<1^1,l,r,x);
			update(o);
		}
	}
	int find(int o,int x) {
		Node &p=nd[o],&lc=nd[o<<1],&rc=nd[o<<1^1];
		if(p.maxx<x) return 0;
		pushdown(o);
		if(lc.maxx>=x) return find(o<<1,x);
		if(p.fix>=x) {
			if(p.l==p.r) {
				solve(1,p.l,p.r,1);
				return p.l;
			}
			int ans=lc.right;
			solve(1,lc.r-ans+1,lc.r,1);
			solve(1,rc.l,rc.l+x-ans-1,1);
			return lc.r-ans+1;
		}
		return find(o<<1^1,x);
	}
}t;
int main() {
	freopen("haoi13t4.in","r",stdin);
	freopen("haoi13t4.out","w",stdout);
	scanf("%d%d",&n,&m);
	t.build(1,1,n);
	int opt,a,b;
	for(int i=1;i<=m;i++) {
		scanf("%d",&opt);
		if(opt==1) scanf("%d",&a),printf("%d\n",t.find(t.root,a));
		else scanf("%d%d",&a,&b),t.solve(t.root,a,a+b-1,0);
	}
	return 0;
}

 

以上是关于[HAOI2013] 软件安装的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ2427: [HAOI2010]软件安装

P2515 [HAOI2010]软件安装

HAOI2010 软件安装

P2515 [HAOI2010]软件安装

BZOJ2427: [HAOI2010]软件安装

[HAOI 2010]软件安装