首页 > 其他分享 >P2894 [USACO08FEB] Hotel G && P3071 [USACO13JAN] Seating G

P2894 [USACO08FEB] Hotel G && P3071 [USACO13JAN] Seating G

时间:2025-01-07 18:43:50浏览次数:6  
标签:P3071 Seating rs int Hotel pos mid ls mx

P2894 [USACO08FEB] Hotel G

P3071 [USACO13JAN] Seating G

题目描述

第一行输入 \(n,m\),\(n\) 代表有 \(n\) 个房间 \((1\leq n \leq 50,000)\),编号为 \(1 \sim n\),开始都为空房,\(m\) 表示以下有 \(m\) 行操作 \((1\leq m < 50,000)\),以下每行先输入一个数 \(i\) ,表示一种操作:

若 \(i\) 为 \(1\),表示查询房间,再输入一个数 \(x\),表示在 \(1,2,...,n\) 房间中找到长度为 \(x\) 的连续空房,输出连续 \(x\) 个房间中左端的房间号,尽量让这个房间号最小,若找不到长度为 \(x\) 的连续空房,输出 \(0\)。若找得到,在这 \(x\) 个空房间中住上人。

若 \(i\) 为 \(2\),表示退房,再输入两个数 \(x,y\) 代表房间号 \(x \sim x+y-1\) 退房,即让房间为空。

你需要对每个输入 \(1\) 输出对应的答案。

Solution:

细节有点多的线段树题。维护一下区间子段和,然后查询的时候由于它寻问的是所有满足条件的区间中左端点的最小值,所以我们在查询时应该取区间的最大子段和的起点 \(t[x].pos\) ,中间两端合并的起点 \(mid-t[ls].rmx+1\) 来更新答案,然后如果左子树满足条件的话就查询左子树,反之查询右子树。如果区间的最大子段和 \(t[x].mx<k\) 的话就直接返回。

然后注意一下pushdownd的细节就可以 AC 本题

Code:

#include<bits/stdc++.h>
const int N=4e5+5;
const int inf=1e9;
using namespace std;
int n,m,cnt,rt;
int a[N];
map<int,int> Map;
//Segment_Tree
struct Tree{
    int lmx,rmx,mx,pos,tag;
    int ls,rs;
}t[N<<4];
#define ls t[x].ls
#define rs t[x].rs
void add(int &x,int l,int r)
{
    if(x)return ;
    x=++cnt;
    t[x].lmx=t[x].rmx=t[x].mx=r-l+1;
    t[x].pos=l;
}
void pushdown(int x,int l,int r)
{
    if(!t[x].tag||l==r)return ;
    int mid=l+r>>1;
    if(!ls)add(ls,l,mid);
    if(!rs)add(rs,mid+1,r);
    if(t[x].tag==1)
    {
        t[x].tag=0;
        t[ls].tag=t[rs].tag=1;
        t[ls].lmx=t[ls].rmx=t[ls].mx=0;
        t[rs].lmx=t[rs].rmx=t[rs].mx=0;
        t[ls].pos=t[rs].pos=inf;
    }
    if(t[x].tag==-1)
    {
        t[x].tag=0;
        t[ls].tag=t[rs].tag=-1;
        t[ls].lmx=t[ls].rmx=t[ls].mx=mid-l+1;
        t[rs].lmx=t[rs].rmx=t[rs].mx=r-mid;
        t[ls].pos=l;
        t[rs].pos=mid+1;
    }

}
void push_up(int x,int l,int r)
{
    int mid=l+r>>1;
    t[x].lmx=t[ls].lmx+ (t[ls].mx==(mid-l+1) ? t[rs].lmx : 0);
    t[x].rmx=t[rs].rmx+ (t[rs].mx==(r-mid)   ? t[ls].rmx : 0);
    t[x].mx=0;t[x].pos=inf;
    if(t[ls].mx>t[x].mx)
    {
        t[x].mx=t[ls].mx;
        t[x].pos=t[ls].pos;
    }
    if(t[ls].rmx+t[rs].lmx==t[x].mx){t[x].pos=min(t[x].pos,mid-t[ls].rmx+1);}
    if(t[ls].rmx+t[rs].lmx>t[x].mx)
    {
        t[x].mx=t[ls].rmx+t[rs].lmx;
        t[x].pos=mid-t[ls].rmx+1;
    }
    if(t[rs].mx>t[x].mx)
    {
        t[x].mx=t[rs].mx;
        t[x].pos=t[rs].pos;
    }
}
void upd(int &x,int l,int r,int L,int R,int k)
{
    if(!x)add(x,l,r);
    if(L<=l&&r<=R)
    {
        if(k)
        {
            t[x].lmx=t[x].rmx=t[x].mx=r-l+1;
            t[x].pos=l;t[x].tag=-1;
        }
        else
        {
            t[x].lmx=t[x].rmx=t[x].mx=0;
            t[x].tag=1;t[x].pos=inf;
        }
        return ;
    }
    int mid=l+r>>1;
    add(ls,l,mid);add(rs,mid+1,r);
    pushdown(x,l,r);
    if(L<=mid)upd(ls,l,mid,L,R,k);
    if(mid<R) upd(rs,mid+1,r,L,R,k);
    push_up(x,l,r);
}
int tag=0;
void query(int x,int l,int r,int k,int &res)
{
    if(t[x].mx<k)return ;
    int mid=l+r>>1;
    res=min(res,t[x].pos);
    //if(t[x].pos==178)cout<<"query:"<<x<<":"<<t[x].pos<<" "<<l<<" "<<r<<" "<<t[ls].lmx<<" "<<t[ls].mx<<" : "<<t[rs].rmx<<" "<<t[rs].mx<<"\n";
    pushdown(x,l,r);
    //if(mid-t[ls].rmx+1==178)cout<<"query:"<<t[x].pos<<" "<<l<<" "<<r<<" "<<t[ls].lmx<<" "<<t[ls].mx<<" : "<<t[rs].rmx<<" "<<t[rs].mx<<"\n";
    if(t[ls].rmx+t[rs].lmx>=k){res=min(res,mid-t[ls].rmx+1);}
    if(t[ls].mx>=k){query(ls,l,mid,k,res);}
    if(t[ls].mx<k&&t[rs].mx>=k){query(rs,mid+1,r,k,res);}
}
void work()
{
    cin>>n>>m;
    add(rt,1,n);
    for(int i=1,k,l,r;i<=m;i++)
    {
        scanf("%d",&k);
        if(k==1)
        {
            tag++;
            scanf("%d",&r);
            //cout<<"k="<<r<<"\n";
            if(t[rt].mx<r){printf("%d\n",0);continue;}
            l=inf;
            query(rt,1,n,r,l);
            r+=l-1;
            upd(rt,1,n,l,r,0);
            //cout<<"book:"<<l<<" "<<r<<"\n";
            printf("%d\n",l);
        }
        else
        {
            scanf("%d%d",&l,&r);
            r+=l-1;
            upd(rt,1,n,l,r,1);
            //cout<<"exit:"<<l<<" "<<r<<"\n";
        }
    }
}
int main()
{
    //freopen("P2894_5.in","r",stdin);freopen("P2894.out","w",stdout);
    work();
    return 0;
}

标签:P3071,Seating,rs,int,Hotel,pos,mid,ls,mx
From: https://www.cnblogs.com/LG017/p/18658151

相关文章

  • [lnsyoj336/luoguP2894/USACO08FEB]Hotel
    题意原题链接给定只包含\(0\)和\(1\)的序列\(a\),支持两种操作:查询\(a\)中最靠左的连续\(x\)个元素均为\(0\)的子串,输出子串的左端点,并将这个子串的所有元素置为\(1\)将\(a\)中以\(x\)开始,长度为\(d\)的子串的所有元素置为\(0\)初始时\(a\)的所有值都为\(0\)sol区间修改,区......
  • P3071 [USACO13JAN] Seating G 题解
    题意:维护两个操作,区间推平,求连续\(0\)的个数为\(x\)的最前位置。线段树。因为需要求连续\(0\)的个数,所以维护区间左边连续\(0\)的最大个数,区间右边连续\(0\)的最大个数以及区间连续\(0\)的最大个数。注意修改的时候要看是修改为\(1\)还是修改为\(0\)。查询的时......
  • P3565 [POI2014] HOT-Hotels
    题目描述:给定一棵树,在树上选\(3\)个点,要求两两距离相等,求方案数。数据范围:\(1\len\le5000\)\(1\lea,b\len\)思路:一开始我想的就是枚举两个点,然后处理第三个点。但是发现这样做非常的不正确,并且非常容易算重,所以我舍去了这种方式。但是在想这种做法的时候,我们会发现,......
  • P3565 [POI2014] HOT-Hotels
    三倍经验:bzoj#3522P3565loj#2431加强版:bzoj#4543先看bzoj#3522这题。容易想到时间\(O(n^2)\),空间\(O(n^2)\)的树形dp。设\(dp_{1/2/3,u,i}\)表示以\(u\)为根的子树中所有以\(u\)为一端点,长度为\(i\)的路径中选\(1/2/3\)条路径的方案数(......
  • [POI2014] HOT-Hotels 加强版
    [POI2014]HOT-Hotels题面翻译给定一棵树,在树上选\(3\)个点,要求两两距离相等,求方案数。题目描述Thereare\(n\)townsinByteotia,connectedwithonly\(n-1\)roads.Eachroaddirectlylinkstwotowns.Alltheroadshavethesamelengthandaretwoway.Itis......
  • hotel数据结构分析
           ......
  • 【题解】CF1854D Michael and Hotel
    交互题。考虑题意即为找到\(1\)所在内向基环树上的所有点。我们考虑我们怎么找到环上的点,我们考虑我们可以\(O(\logn)\)询问到一个环上的点,方法即为将\(k\)定为一个大数,然后二分点集。然后我们便可以在\(O(n\logn)\)的时间复杂度内找到所有环上的点(我们一会儿再讲怎......
  • P5904 [POI2014] HOT-Hotels 加强版
    自然的想法是枚举共同的交点,然后进行换根dp,复杂度可以做到\(\mathcalO(n^2)\),可以通过简单版,但是显然过不了\(10^5\)的数据,考虑进行优化。记\((x,y,z)\)为满足要求的点,即满足\(a=b+c\),树形dp原则是子树内的信息无后效性,尽量把子树内的信息合并在一起。所以\(a-b=c\),......
  • 洛谷 P2894 [USACO08FEB] Hotel G 题解
    题目链接P2894[USACO08FEB]HotelG-洛谷|计算机科学教育新生态(luogu.com.cn)分析考虑用线段树维护区间信息维护sum(最大连续空房间数)如何合并?sum1为max(sum2,sum3)(1的两个子区间)但我们发现若区间为100001(0表示空房间)sum1=4而max(sum2,sum3)=2所以再维护suml(从左开始的......
  • 题解 BZOJ4543【[POI2014] HOT-Hotels】
    长链剖分优化DP板子题了,但是虽然是板子这个转移方程也很难想。problem树。求\(\sum_{1\leqi<j<k\leqn}[dist(i,j)=dist(i,k)=dist(j,k)].\)。\(n\leq10^5\)。solution与重链剖分相似,长链剖分是将树剖成很多条长链。我们定义长儿子,为一个点的儿子中子树深度最大的一个儿......