约会安排 HDU

Posted acmloser

tags:

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

原题链接
考察:线段树
思路:
  如果做过校门外的树(增强版)那道题,应该可以想到是建立两个线段树.一个维护基友和女神约会时间tr[0],一个维护女神时间tr[1].
  对于基友相约t,我们求出tr[0]的t个空白时间的最左端点,然后更新tr[0];对于女神相约t,先求出tr[0]的左端点,没有就求tr[1]的左端点.更新tr[1]与tr[0].对于虚假的学习,两个都做清空操作.
  接下来就是考虑怎么求最左端点.这实际上是求出长度至少为t的空闲连续区间(最大连续子段).考虑设置Ls(从左端点出发的最大连续长度),Rs(同理).那么这个空闲区间可能在

  1. 左子区间内部.
  2. 左子区间右子区间中间.
  3. 右子区间内部.
      这就是和那道连通村庄一样的求解方式了.
      为了方便判断是否可行,可以再维护一个变量sum,指[l,r]区间内最大的连续长度.
      此题细节超多,比如push_up与push_down
      然后就是存不存在使用的tr[s][1].sum是还未更新的.答案是不存在,我们每次进行相应操作,都会更新相应的tr[s][1],我们怎么修改基友占用时间,都不会对女神线段树造成影响.

Code

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010,M = 10;
char op[M];
int n,m;
struct Node{
	int l,r,Ls,Rs,sum,tag;//ls以左端点空白时间 ,Rs以右端点空白时间,整个区间的最大连续空白时间 
}tr[2][N<<2];//0:女神+基友 1:女神 
int get(int u)
{
	return tr[0][u].r-tr[0][u].l+1;
}
void push_up(int u,int s)
{
	tr[s][u].Ls = tr[s][u<<1].Ls+(tr[s][u<<1].Ls==get(u<<1)?tr[s][u<<1|1].Ls:0);
	tr[s][u].Rs = tr[s][u<<1|1].Rs+(tr[s][u<<1|1].Rs==get(u<<1|1)?tr[s][u<<1].Rs:0);
	tr[s][u].sum = max(tr[s][u<<1].sum,tr[s][u<<1|1].sum);
	tr[s][u].sum = max(tr[s][u<<1].Rs+tr[s][u<<1|1].Ls,tr[s][u].sum);
}
void push_down(int u,int s)
{
	if(tr[s][u].tag==1)
	{
		tr[s][u<<1].Ls = tr[s][u<<1].Rs = tr[s][u<<1].sum = get(u<<1);
		tr[s][u<<1|1].Ls = tr[s][u<<1|1].Rs = tr[s][u<<1|1].sum = get(u<<1|1);
		tr[s][u<<1].tag = tr[s][u<<1|1].tag = tr[s][u].tag;
		tr[s][u].tag = 0;
	}
	if(tr[s][u].tag==-1)
	{
		tr[s][u<<1].Ls = tr[s][u<<1].Rs = tr[s][u<<1].sum = 0;
		tr[s][u<<1|1].Ls = tr[s][u<<1|1].Rs = tr[s][u<<1|1].sum = 0;
		tr[s][u<<1].tag = tr[s][u<<1|1].tag = tr[s][u].tag;
		tr[s][u].tag = 0;
	}
}
void build(int u,int l,int r)
{
	tr[0][u] = {l,r,1,1,1,0}; tr[1][u] = {l,r,1,1,1,0};
	if(l==r) return;
	int mid = l+r>>1;
	build(u<<1,l,mid); build(u<<1|1,mid+1,r);
	push_up(u,0); push_up(u,1);
}
int findL(int u,int s,int c)//清空操作会破坏连续性,所以要维护Rs 
{
	if(tr[s][u].l==tr[s][u].r) return tr[s][u].l;
	int mid = tr[s][u].l+tr[s][u].r>>1;
	push_down(u,s);
	if(tr[s][u<<1].sum>=c) return findL(u<<1,s,c);
	else if(tr[s][u<<1].Rs+tr[s][u<<1|1].Ls>=c) return mid-tr[s][u<<1].Rs+1;
	else return findL(u<<1|1,s,c);
}
void modify(int u,int l,int r,int s)//清零 
{
	if(tr[s][u].l>=l&&tr[s][u].r<=r)
	{
		tr[s][u].Ls = tr[s][u].Rs = tr[s][u].sum = 0;
		tr[s][u].tag = -1;
		return;
	}
	push_down(u,s);
	int mid = tr[s][u].l+tr[s][u].r>>1;
	if(l<=mid) modify(u<<1,l,r,s);
	if(mid<r) modify(u<<1|1,l,r,s);
	push_up(u,s);
}
void clearT(int u,int l,int r,int s)
{
	if(tr[s][u].l>=l&&tr[s][u].r<=r)
	{
		tr[s][u].Ls = tr[s][u].Rs = tr[s][u].sum = get(u);
		tr[s][u].tag = 1;
		return;
	}
	push_down(u,s);
	int mid = tr[s][u].l+tr[s][u].r>>1;
	if(l<=mid) clearT(u<<1,l,r,s);
	if(mid<r) clearT(u<<1|1,l,r,s);
	push_up(u,s);
}
int main()
{
	int T,kcase=0;
	scanf("%d",&T);
	while(T--)
	{
		printf("Case %d:\\n",++kcase);
		scanf("%d%d",&n,&m);
		build(1,1,n);
		while(m--)
		{
			int c,d;
			scanf("%s%d",op,&c);
			if(op[0]==\'D\')
			{
				if(tr[0][1].sum<c) {printf("fly with yourself\\n");continue;} 
				int L = findL(1,0,c);
				modify(1,L,L+c-1,0);
				printf("%d,let\'s fly\\n",L);
			}else if(op[0]==\'N\')
			{
				int s = -1;
				if(tr[0][1].sum>=c) s = 0;
				else if(tr[1][1].sum>=c) s = 1;
				if(s==-1) {puts("wait for me");continue;} 
				int L = findL(1,s,c);
				printf("%d,don\'t put my gezi\\n",L);
				modify(1,L,L+c-1,1),modify(1,L,L+c-1,0);
			}else if(op[0]==\'S\')
			{
				scanf("%d",&d);
				puts("I am the hope of chinese chengxuyuan!!");
				clearT(1,c,d,0); clearT(1,c,d,1);
			}
		}
	}
	return 0;
}

以上是关于约会安排 HDU的主要内容,如果未能解决你的问题,请参考以下文章

约会安排 HDU - 4553

HDU 4553 约会安排 (区间合并)线段树

约会安排 HDU

HDU 4553 约会安排(线段树区间合并+双重标记)

hdu 4553 约会安排 (两个线段树维护区间)

M - 约会安排 HDU - 4553 线段树 (最长连续段)