题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553
解题思路:
①题目的意思是询问当前是否能够给出空余的一段连续时间,并且这段时间尽可能靠前。
需要两棵树,一棵屌丝+女神,另一棵女神
对于屌丝询问第一棵树有无这样一段连续时间,有就更新第一棵树,没有就不约
对于女神先询问第一棵树,第一棵树有就约会,如果第一棵树没有符合的区间,查询第二棵树有就约。最后更新两棵树对应求出的区间。
还有一个清空操作,清空两棵树对应区间即可。
②因为两棵树模式一样,分析一棵就行了。
如何才能查找到区间内最靠左的符合条件的区间呢?
肯定要利用DFS的性质,让搜索可以“可以左就先左,左到不能再搜右”
让线段树维护区间最长连续长度,以及从左往右,从右往左的最长连续长度。
现在我们假设线段树已经维护了这些东西,再假设需要一段长度为x的时间,那么:
如果(if)左子树的最长连续长度>=x,那么就搜左子树
否则如果(else if)看左子树右到左+右子树左到右>=z,那么更新一次这里的答案
再否则如果(else if)右子树最长连续长度>=x,搜右子树
按照这样的思路搜索,尽量让答案向左靠近
③如果不清楚维护区间连续最大和的方法请看代码中的push_up()函数
#define dl ds[rt<<1]
#define dr ds[rt<<1|1]
void push_up(int rt,T ds[])
{
ds[rt].l = (dl.l==dl.len)? dl.len+dr.l : dl.l;
ds[rt].r = (dr.r==dr.len)? dr.len+dl.r : dr.r;
ds[rt].ans = max(max(dl.ans,dr.ans),dl.r+dr.l);
}
l表示左到右最大连续,r表示右到左最大连续,ans表示区间最大连续
④然后因为都是区间修改,那么就要涉及push_down()也就是下放函数了。
由于区间要么整体清0,要么整体全1,所以在区间和等于0,或者等于区间长度时,下放就可以了。只有这两种情况是修改到这一层没继续下更新的情况。
⑤query函数if(l==r)的判断很重要,不然叶子下放直接GG(奥义之无限RE别问我为什么要提醒你)
代码1(愚蠢加长版):
#include
#include
#include
#define ll long long
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
#define dl ds[rt<<1]
#define dr ds[rt<<1|1]
#define nl ns[rt<<1]
#define nr ns[rt<<1|1]
using namespace std;
const int N = 1e5+5;
struct T
{
int l,r,len,ans;
}ds[N<<2],ns[N<<2];
int ans;
void push_up(int rt,int op)
{
if (op==1){
ds[rt].l = (dl.l==dl.len)? dl.len+dr.l : dl.l;
ds[rt].r = (dr.r==dr.len)? dr.len+dl.r : dr.r;
ds[rt].ans = max(max(dl.ans,dr.ans),dl.r+dr.l);
}
else {
ns[rt].l = (nl.l==nl.len)? nl.len+nr.l : nl.l;
ns[rt].r = (nr.r==nr.len)? nr.len+nl.r : nr.r;
ns[rt].ans = max(max(nl.ans,nr.ans),nl.r+nr.l);
}
}
void push_down(int rt,int op)///区间0,区间1
{
if (op==1){
if (ds[rt].ans == 0){
dl.l = dl.r = dr.l = dr.r = dl.ans = dr.ans = 0;
}
if (ds[rt].ans == ds[rt].len){
int len = ds[rt].len;
dl.ans = dl.l = dl.r = (len-len/2);
dr.ans = dr.l = dr.r = len/2;
}
}
else {
if (ns[rt].ans == 0){
nl.l = nl.r = nr.l = nr.r = nl.ans = nr.ans = 0;
}
if (ns[rt].ans == ns[rt].len){
int len = ns[rt].len;
nl.ans = nl.l = nl.r = (len-len/2);
nr.ans = nr.l = nr.r = len/2;
}
}
}
void query(int x,int op,int rt,int l,int r)
{
if (l==r){
ans = min(ans,l);
return ;
}
mid;
push_down(rt,op);
if (op==1){
if (dl.ans >= x) query(x,op,lson);
else if (dl.r+dr.l >= x) ans = min(ans,m-dl.r+1);
else if (dr.ans >= x) query(x,op,rson);
}
if (op==2){
if (nl.ans >= x) query(x,op,lson);
else if (nl.r+nr.l >= x) ans = min(ans,m-nl.r+1);
else if (nr.ans >= x) query(x,op,rson);
}
}
void update(int L,int R,int x,int op,int rt,int l,int r)
{
if (L<=l && r<=R){
if (op==1){
if (x==0) ds[rt].ans = ds[rt].l = ds[rt].r = 0;
else ds[rt].ans = ds[rt].l = ds[rt].r = r-l+1;
}
if (op==2){
if (x==0) ns[rt].ans = ns[rt].l = ns[rt].r = 0;
else ns[rt].ans = ns[rt].l = ns[rt].r = r-l+1;
}
return ;
}
mid;
push_down(rt,op);
if (L<=m) update(L,R,x,op,lson);
if (R>m) update(L,R,x,op,rson);
push_up(rt,op);
}
void build(int rt,int l,int r)
{
if (l==r){
ds[rt].ans = ds[rt].l = ds[rt].r = ds[rt].len = 1;
ns[rt].ans = ns[rt].l = ns[rt].r = ns[rt].len = 1;
return ;
}
mid;
build(lson);
build(rson);
push_up(rt,1);
push_up(rt,2);
ds[rt].len = dl.len + dr.len;
ns[rt].len = nl.len + nr.len;
}
int main()
{
int T,n,m;
scanf("%d",&T);
int kca = 1;
while (T--){
printf("Case %d:\n",kca++);
scanf("%d %d",&n,&m);
build(1,1,n);
char op[10];
int l,r,len;
while (m--){
scanf("%s",op);
if (op[0]=='S'){
scanf("%d %d",&l,&r);
printf("I am the hope of chinese chengxuyuan!!\n");
update(l,r,1,1,1,1,n);
update(l,r,1,2,1,1,n);
}
else {
scanf("%d",&len);
ans = n*2;///初始化为一个很大的数
if (op[0]=='D'){
query(len,1,1,1,n);
if (ans==n*2) printf("fly with yourself\n");
else {
printf("%d,let's fly\n",ans);
update(ans,ans+len-1,0,1,1,1,n);
}
}
else {
query(len,1,1,1,n);
if (ans==n*2) query(len,2,1,1,n);
if (ans==n*2) printf("wait for me\n");
else {
printf("%d,don't put my gezi\n",ans);
update(ans,ans+len-1,0,1,1,1,n);
update(ans,ans+len-1,0,2,1,1,n);
}
}
}
}
}
return 0;
}
代码2(略微精简版):
#include
#include
#include
#define ll long long
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
#define dl ds[rt<<1]
#define dr ds[rt<<1|1]
#define nl ns[rt<<1]
#define nr ns[rt<<1|1]
using namespace std;
const int N = 1e5+5;
struct T
{
int l,r,len,ans;
}ds[N<<2],ns[N<<2];
int ans;
void push_up(int rt,T ds[])
{
ds[rt].l = (dl.l==dl.len)? dl.len+dr.l : dl.l;
ds[rt].r = (dr.r==dr.len)? dr.len+dl.r : dr.r;
ds[rt].ans = max(max(dl.ans,dr.ans),dl.r+dr.l);
}
void push_down(int rt,T ds[])
{
if (ds[rt].ans == 0){
dl.l = dl.r = dr.l = dr.r = dl.ans = dr.ans = 0;
}
if (ds[rt].ans == ds[rt].len){
int len = ds[rt].len;
dl.ans = dl.l = dl.r = (len-len/2);
dr.ans = dr.l = dr.r = len/2;
}
}
void query(int x,T ds[],int rt,int l,int r)
{
if (l==r){
ans = min(ans,l);
return ;
}
mid;
push_down(rt,ds);
if (dl.ans >= x) query(x,ds,lson);
else if (dl.r+dr.l >= x) ans = min(ans,m-dl.r+1);
else if (dr.ans >= x) query(x,ds,rson);
}
void update(int L,int R,int x,T ds[],int rt,int l,int r)
{
if (L<=l && r<=R){
if (x==0) ds[rt].ans = ds[rt].l = ds[rt].r = 0;
else ds[rt].ans = ds[rt].l = ds[rt].r = r-l+1;
return ;
}
mid;
push_down(rt,ds);
if (L<=m) update(L,R,x,ds,lson);
if (R>m) update(L,R,x,ds,rson);
push_up(rt,ds);
}
void build(int rt,int l,int r)
{
if (l==r){
ds[rt].ans = ds[rt].l = ds[rt].r = ds[rt].len = 1;
ns[rt].ans = ns[rt].l = ns[rt].r = ns[rt].len = 1;
return ;
}
mid;
build(lson);
build(rson);
push_up(rt,ds);
push_up(rt,ns);
ds[rt].len = dl.len + dr.len;
ns[rt].len = nl.len + nr.len;
}
int main()
{
int T,n,m;
scanf("%d",&T);
int kca = 1;
while (T--){
printf("Case %d:\n",kca++);
scanf("%d %d",&n,&m);
build(1,1,n);
char op[10];
int l,r,len;
while (m--){
scanf("%s",op);
if (op[0]=='S'){
scanf("%d %d",&l,&r);
printf("I am the hope of chinese chengxuyuan!!\n");
update(l,r,1,ds,1,1,n);
update(l,r,1,ns,1,1,n);
}
else {
scanf("%d",&len);
ans = n*2;///初始化为一个很大的数
if (op[0]=='D'){
query(len,ds,1,1,n);
if (ans==n*2) printf("fly with yourself\n");
else {
printf("%d,let's fly\n",ans);
update(ans,ans+len-1,0,ds,1,1,n);
}
}
else {
query(len,ds,1,1,n);
if (ans==n*2) query(len,ns,1,1,n);
if (ans==n*2) printf("wait for me\n");
else {
printf("%d,don't put my gezi\n",ans);
update(ans,ans+len-1,0,ds,1,1,n);
update(ans,ans+len-1,0,ns,1,1,n);
}
}
}
}
}
return 0;
}
总结:
目前做到的维护区间连续的题目有三道:(题解都有写)
HDU 1540
Vijos 1083
以及这一题。
维护区间连续也是线段树一大功能啊。
其中的精髓就是通过区间合并得出任意区间对应的信息。
基本上涉及到区间连续性就要用这个思路啦。一左一右一整体。
不过这题的思路感觉还是比较清奇,应该是 利用DFS+线段树维护连续性。