题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553
题目大意:查找是否有连续的空余时间
他的操作有三个 :
ds x 查找屌丝的时间有连续的x长度的空余时间
ns x 为女神安排时间,先查找屌丝时间是否有空余,没有的话无视屌丝,直接判断女神时间是否有连续x长的空余时间
stduy a b 清空a到b区间的事情
思路:
一:存线段树数据的数组要有九个变量。
struct node
{
int d,n,s;//d屌丝延迟标记 n女神延迟标记 s学习延迟标记
int ls,rs,ms;//屌丝的左 右 区间最大的连续空时间的长
int nsl,nsr,nsm;//女神的左 右 区间最大的连续空时间的长
} a[L<<2];
二:关于pushdown函数
void pushdown(int l,int r,int rt)//延迟标记的向下传递
{
int m = (l+r)>>1;
if(a[rt].s)
{
xuexi(lson);
xuexi(rson);
a[rt].s = 0;
}
if(a[rt].d)
{
diaosi(lson);
diaosi(rson);
a[rt].d = 0;
}
if(a[rt].n)
{
nvshen(lson);
nvshen(rson);
a[rt].n = 0;
}
}
pushdown函数是将延迟标记的信息向下传递
而延迟标记有三种 学习,屌丝,女神,注意学习标记优先级最大
分别对每种标记有如下的操作:
void diaosi(int l,int r,int rt)//屌丝的延迟标记处理
{
a[rt].d = 1;
a[rt].ls = a[rt].rs = a[rt].ms = 0;
}
void nvshen(int l,int r,int rt)//女神的延迟标记处理 不仅要将屌丝时间占据 女神时间也要占据
{
a[rt].n = 1;
a[rt].d = 0;
a[rt].ls = a[rt].rs = a[rt].ms = 0;
a[rt].nsl = a[rt].nsr = a[rt].nsm = 0;
}
void xuexi(int l,int r,int rt)//学习延迟标记 全部清理成空的时间
{
a[rt].s = 1;
a[rt].d = a[rt].n = 0;
a[rt].ls = a[rt].rs = a[rt].ms = r-l+1;
a[rt].nsl = a[rt].nsr = a[rt].nsm = r-l+1;
}
这里需要特别注意的是女神标记的处理,他不仅要对自己女神时间进行处理,同时也要对相应的屌丝时间进行处理
三:关于pushup函数
void pushup(int l,int r,int rt)//屌丝和女神区间的合并
{
int mid = (l+r)>>1;
int m=r-l+1;
a[rt].ms = max(a[rt<<1].ms,a[rt<<1|1].ms);
a[rt].ms = max(a[rt].ms,a[rt<<1].rs+a[rt<<1|1].ls);
a[rt].ls = a[rt<<1].ls;
a[rt].rs = a[rt<<1|1].rs;
if(a[rt<<1].ls == m-(m>>1))
a[rt].ls+=a[rt<<1|1].ls;
if(a[rt<<1|1].rs == (m>>1))
a[rt].rs+= a[rt<<1].rs;
a[rt].nsm = max(a[rt<<1].nsm,a[rt<<1|1].nsm);
a[rt].nsm = max(a[rt].nsm,a[rt<<1].nsr+a[rt<<1|1].nsl);
a[rt].nsl = a[rt<<1].nsl;
a[rt].nsr = a[rt<<1|1].nsr;
if(a[rt<<1].nsl == m-(m>>1))
a[rt].nsl+=a[rt<<1|1].nsl;
if(a[rt<<1|1].nsr ==(m>>1))
a[rt].nsr+= a[rt<<1].nsr;
}
这个就是一个典型的区间合并 女神和屌丝同样处理
四:查找连续长度为t的连续区间 注意一个是屌丝查询 一个是女神查询 分开处理
int query(int flag,int t,int l,int r,int rt)
{
if(l==r)
return l;
int m = (l+r)>>1;
pushdown(l,r,rt);
if(!flag)//屌丝时间查询
{
if(a[rt<<1].ms>=t)//左子树有时间
return query(flag,t,lson);
else if(a[rt<<1].rs+a[rt<<1|1].ls>=t)//左子树部分加右子树部分
return m-a[rt<<1].rs+1;
else//右子树有时间
return query(flag,t,rson);
}
else//女神时间查询 直接无视屌丝
{
if(a[rt<<1].nsm>=t)
return query(flag,t,lson);
else if(a[rt<<1].nsr+a[rt<<1|1].nsl>=t)
return m-a[rt<<1].nsr+1;
else
return query(flag,t,rson);
}
}
因为要求时间尽可能早,所有从左子树开始查询,然后左部分加右部分,最后是右子树
五:对区间进行处理 将其覆盖成屌丝时间或者女神时间
void insert(int flag,int L,int R,int l,int r,int rt)
{
if(l == L && r == R)
{
if(!flag)//将那段时间设为屌丝时间
diaosi(l,r,rt);
else//将那段时间设为女神时间
nvshen(l,r,rt);
return ;
}
int m = (l+r)>>1;
pushdown(l,r,rt);
if(R<=m)
insert(flag,L,R,lson);
else if(L>m)
insert(flag,L,R,rson);
else
{
insert(flag,L,m,lson);
insert(flag,m+1,R,rson);
}
pushup(l,r,rt);
}
接下里是完整的ac代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int L = 100000+10;
struct node
{
int d,n,s;//d屌丝延迟标记 n女神延迟标记 s学习延迟标记
int ls,rs,ms;//屌丝的左 右 区间最大的连续空时间的长
int nsl,nsr,nsm;//女神的左 右 区间最大的连续空时间的长
} a[L<<2];
void diaosi(int l,int r,int rt)//屌丝的延迟标记处理
{
a[rt].d = 1;
a[rt].ls = a[rt].rs = a[rt].ms = 0;
}
void nvshen(int l,int r,int rt)//女神的延迟标记处理 不仅要将屌丝时间占据 女神时间也要占据
{
a[rt].n = 1;
a[rt].d = 0;
a[rt].ls = a[rt].rs = a[rt].ms = 0;
a[rt].nsl = a[rt].nsr = a[rt].nsm = 0;
}
void xuexi(int l,int r,int rt)//学习延迟标记 全部清理成空的时间
{
a[rt].s = 1;
a[rt].d = a[rt].n = 0;
a[rt].ls = a[rt].rs = a[rt].ms = r-l+1;
a[rt].nsl = a[rt].nsr = a[rt].nsm = r-l+1;
}
void pushup(int l,int r,int rt)//屌丝和女神区间的合并
{
int mid = (l+r)>>1;
int m=r-l+1;
a[rt].ms = max(a[rt<<1].ms,a[rt<<1|1].ms);
a[rt].ms = max(a[rt].ms,a[rt<<1].rs+a[rt<<1|1].ls);
a[rt].ls = a[rt<<1].ls;
a[rt].rs = a[rt<<1|1].rs;
if(a[rt<<1].ls == m-(m>>1))
a[rt].ls+=a[rt<<1|1].ls;
if(a[rt<<1|1].rs == (m>>1))
a[rt].rs+= a[rt<<1].rs;
a[rt].nsm = max(a[rt<<1].nsm,a[rt<<1|1].nsm);
a[rt].nsm = max(a[rt].nsm,a[rt<<1].nsr+a[rt<<1|1].nsl);
a[rt].nsl = a[rt<<1].nsl;
a[rt].nsr = a[rt<<1|1].nsr;
if(a[rt<<1].nsl == m-(m>>1))
a[rt].nsl+=a[rt<<1|1].nsl;
if(a[rt<<1|1].nsr ==(m>>1))
a[rt].nsr+= a[rt<<1].nsr;
}
void pushdown(int l,int r,int rt)//延迟标记的向下传递
{
int m = (l+r)>>1;
if(a[rt].s)
{
xuexi(lson);
xuexi(rson);
a[rt].s = 0;
}
if(a[rt].d)
{
diaosi(lson);
diaosi(rson);
a[rt].d = 0;
}
if(a[rt].n)
{
nvshen(lson);
nvshen(rson);
a[rt].n = 0;
}
}
void study(int L,int R,int l,int r,int rt)
{
if(L == l && R == r)
{
xuexi(l,r,rt);
return ;
}
int m = (l+r)>>1;
pushdown(l,r,rt);
if(R<=m)
study(L,R,lson);
else if(L>m)
study(L,R,rson);
else
{
study(L,m,lson);
study(m+1,R,rson);
}
pushup(l,r,rt);
}
void insert(int flag,int L,int R,int l,int r,int rt)
{
if(l == L && r == R)
{
if(!flag)//将那段时间设为屌丝时间
diaosi(l,r,rt);
else//将那段时间设为女神时间
nvshen(l,r,rt);
return ;
}
int m = (l+r)>>1;
pushdown(l,r,rt);
if(R<=m)
insert(flag,L,R,lson);
else if(L>m)
insert(flag,L,R,rson);
else
{
insert(flag,L,m,lson);
insert(flag,m+1,R,rson);
}
pushup(l,r,rt);
}
int query(int flag,int t,int l,int r,int rt)
{
if(l==r)
return l;
int m = (l+r)>>1;
pushdown(l,r,rt);
if(!flag)//屌丝时间查询
{
if(a[rt<<1].ms>=t)//左子树有时间
return query(flag,t,lson);
else if(a[rt<<1].rs+a[rt<<1|1].ls>=t)//左子树部分加右子树部分
return m-a[rt<<1].rs+1;
else//右子树有时间
return query(flag,t,rson);
}
else//女神时间查询 直接无视屌丝
{
if(a[rt<<1].nsm>=t)
return query(flag,t,lson);
else if(a[rt<<1].nsr+a[rt<<1|1].nsl>=t)
return m-a[rt<<1].nsr+1;
else
return query(flag,t,rson);
}
}
int main()
{
int t,i,x,y,ans,cas = 1,n,m;
char str[20];
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
printf("Case %d:\n",cas++);
study(1,n,1,n,1); //区间1~n全部清零
while(m--)
{
scanf("%s",str);
if(str[0] == 'D')
{
scanf("%d",&x);
if(a[1].ms<x)//线段树最大的区间都小于给定的时间就不用找了
printf("fly with yourself\n");
else
{
ans = query(0,x,1,n,1);//查询到位置
insert(0,ans,ans+x-1,1,n,1);
printf("%d,let's fly\n",ans);
}
}
else if(str[0] == 'N')
{
scanf("%d",&x);
if(a[1].ms<x)//屌丝时间找不到空余时间
{
if(a[1].nsm<x)//判断女神时间是否有空余
printf("wait for me\n");
else
{
ans = query(1,x,1,n,1);//先查找位置
insert(1,ans,ans+x-1,1,n,1);//然后对其区间进行更新
printf("%d,don't put my gezi\n",ans);
}
}
else
{
ans = query(0,x,1,n,1);
insert(1,ans,ans+x-1,1,n,1);
printf("%d,don't put my gezi\n",ans);
}
}
else
{
scanf("%d%d",&x,&y);
study(x,y,1,n,1);
printf("I am the hope of chinese chengxuyuan!!\n");
}
}
}
return 0;
}