P3968 [TJOI2014] 电源插排

P3968 [TJOI2014] 电源插排

题目描述

小 M 的实验室有很多电源插排。这些插排的编号从 \(1\)\(n\),由左向右排成一排。

每天早晨,这些插排都是没有被使用的。每当一个学生来到实验室,他就将自己的笔记本电源插到某一个未被使用的插排上。

实验室的同学们都很奇怪,他们完成这个过程是这样的:首先,他们找到还没有被使用的插排的最长区间。

如果有多个区间长度相同,他们就选择最靠右的那个。然后将自己的电源插到该区间的中间。

如果区间长度是偶数,他们同样选择靠右的那个。当一个同学离开实验室时,他会将自己的电源拔出来。

数据保证每一个同学来到实验室时,至少有一个空的插排。

需要计算在区间 \([l,r]\) 已经有多少个插排被使用了。

输入格式

第一行是两个整数 \(n\)\(q\),表示插排数量和询问数量。

接下来 \(q\) 行,每一行以一个整数 \(k\) 开头。

如果 \(k\)\(0\),接下来就是两个整数 \(l\)\(r\),表示一个询问。

否则 \(k\) 表示表示编号为 \(k\) 的学生到来或离开。\(k\) 的奇数次出现表示到来,偶数次出现表示离开。每个学生的编号都是唯一的。

输出格式

对于每一个询问,输出一个整数,表示询问区间内有多少个插排已经被使用。

Solution:

非常有意思的线段树题,我们考虑动态开点维护一颗线段树以维护区间最长连续0序列的长度及其中点坐标还有当前区间下有多少个插排正在使用

首先,对于n=1e9的数据我们显然不能也不需要将每个点都开全,我们只需要知道一些区间上的最长0序列,所以我们只需要在update的时候新开节点就好了

然后我们可以敏锐的察觉到这题的关键就在于push_up:

push_up:

int mid=l+r>>1;
    t[x].cnt=t[ls].cnt+t[rs].cnt;
    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;
    if(t[rs].mx>t[x].mx)
    {
        t[x].mx=t[rs].mx;
        t[x].mid=t[rs].mid;
    }
    if(t[ls].rmx+t[rs].lmx>t[x].mx)
    {
        t[x].mx=t[ls].rmx+t[rs].lmx;
        t[x].mid=mid-t[ls].rmx+1+(t[x].mx/2);
    }
    if(t[ls].mx>t[x].mx)
    {
        t[x].mx=t[ls].mx;
        t[x].mid=t[ls].mid;
    }

看完代码我们不难发现,除了左右区间合并取得最大值时的mid我们比较难思考,剩下的和最长0序列/最大子段和一类题目的写法几乎没有区别
所以我们来重点推一下

if(t[ls].rmx+t[rs].lmx>t[x].mx)
    {
        t[x].mx=t[ls].rmx+t[rs].lmx;
        t[x].mid=mid-t[ls].rmx+1+(t[x].mx/2);
    }

mid是当前区间的中点,也是t[ls].rmx结束的地方,所以
\(mid-t[ls].rmx+1\)表示的就是t[ls].rmx开始的地方
然后\(t[x].mx/2\)显然就是区间长度(向下取整)但是这题让我们维护的中点貌似是向上取整的啊qwq
但是我们有不难发现,我们的t[x].mid取的是
\(l+ (len/2)\) 而非 \(l+(len/2)-1\)
也就是说,我们是在左闭端点上加了区间长度的一半(向下取整)这样我们取到的中点应该是向上取整的

然后这题貌似就做完了,但是还有一个十分坑的点:

“?”判断的优先级在"="号之后,例如:

t[x].lmx=t[ls].lmx+ (t[ls].mx==(mid-l+1) ? t[rs].lmx : 0);

不等价于

t[x].lmx=t[ls].lmx+ t[ls].mx==(mid-l+1) ? t[rs].lmx : 0;

前者会先判断问号语法内的bool并返回相应的值,而后者会直接忽略“+”号之后的内容

至于我为什么知道嘛...

十七岁花季少年竟然为了它破防7小时

我是永远不会承认我们数据结构选手目光呆滞的

Code:

#include<bits/stdc++.h>
const int N=4e5+5;
using namespace std;
int n,m,cnt,rt;
int a[N];
map<int,int> Map;
//Segment_Tree
struct Tree{
    int lmx,rmx,mx,cnt,mid;
    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].mid=l+r+1>>1;
}
void push_up(int x,int l,int r)
{
    int mid=l+r>>1;
    t[x].cnt=t[ls].cnt+t[rs].cnt;
    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;
    if(t[rs].mx>t[x].mx)
    {
        t[x].mx=t[rs].mx;
        t[x].mid=t[rs].mid;
    }
    if(t[ls].rmx+t[rs].lmx>t[x].mx)
    {
        t[x].mx=t[ls].rmx+t[rs].lmx;
        t[x].mid=mid-t[ls].rmx+1+(t[x].mx/2);
    }
    if(t[ls].mx>t[x].mx)
    {
        t[x].mx=t[ls].mx;
        t[x].mid=t[ls].mid;
    }
}
void upd(int &x,int l,int r,int pos,int k)
{
    if(!x)add(x,l,r);
    if(l==r)
    {
        t[x].lmx=t[x].rmx=t[x].mx=!k;
        t[x].cnt=k;
        return ;
    }
    int mid=l+r>>1;
    add(ls,l,mid);add(rs,mid+1,r);
    if(pos<=mid)upd(ls,l,mid,pos,k);
    else upd(rs,mid+1,r,pos,k);
    push_up(x,l,r);
}
void query(int x,int l,int r,int L,int R,int &res)
{
    if(!x)return ;
    if(L<=l&&r<=R)
    {
        res+=t[x].cnt;
        return ;
    }
    int mid=l+r>>1;
    if(L<=mid)query(ls,l,mid,L,R,res);
    if(mid<R) query(rs,mid+1,r,L,R,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)
        {
            if(Map[k])
            {
                upd(rt,1,n,Map[k],0);
                Map[k]=0;
            }
            else
            {
                Map[k]=t[rt].mid;upd(rt,1,n,Map[k],1);
            }
        }
        else
        {
            scanf("%d%d",&l,&r);
            int ans=0;query(rt,1,n,l,r,ans);
            printf("%d\n",ans);
        }
    }
}
int main()
{
    //freopen("P3968.in","r",stdin);freopen("P3968.out","w",stdout);
    work();
    return 0;
}
posted @ 2024-12-06 11:56  liuboom  阅读(19)  评论(0)    收藏  举报