zoukankan      html  css  js  c++  java
  • CodeForces 1418D Trash Problem

    题意

    数轴上有 (n) 个点,每一次你可以将所有位置在 (x) 的点移动到 (x-1) 或者是移动到 (x+1),花费为 (1)

    (q) 次操作,每一次会在数轴上添加一个原来没有的点或者是删除一个原来已经有的点。在所有操作前和每一次操作后你需要回答将所有点集中到不超过两个点的最小花费。

    ( exttt{Data Range:}1leq n,qleq 10^5)

    前言

    你打开了本题。

    你发现是已经写过了 (998244353) 遍的维护最大的邻项之差。

    你熟练的写出了代码,但是发现需要分类讨论,很头疼。

    你翻开了题解,发现题解也是分类讨论。

    相信经历了这么多的你心中满满的“我太难了”。

    那么这篇题解将拯救你于水火之中(?)

    题解

    注意到肯定是左边一段的点放在一起右边一段的点放在一起。

    假设当前一共有 (n) 个点,从小到大依次为 (p_1,cdots,p_n),考虑让 (p_1,cdots,p_k) 放在一起,(p_{k+1},cdots,p_n) 放在一起,那么花费为 (p_k-p_1+p_n-p_{k+1}=(p_n-p_1)-(p_{k+1}-p_k))

    注意到对于每一个加点删点的操作来说 (p_n-p_1) 很容易维护,然后 (p_{k+1}-p_k) 就是开个 multiset 维护最大差值就完了。

    但是这东西需要分类讨论很麻烦,所以我们想个办法让维护这东西变得很轻松不需要分类讨论。

    考虑 Splay 预处理的时候往里面加 (infty)(-infty),所以我们也可以往里面加 (infty)(-infty)

    然后询问的时候最大的两个绝对是 (p_1-(-infty))(infty-p_n),于是只需要查询第三大的那个就好了,没有第三大的答案就是 (0)

    这么写可以规避各种各样的分类讨论,比如说什么新插入的值没有前驱后继啦,什么插入点之前 multiset 里元素不够啦什么的,何乐而不为呢?

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int ll;
    const ll MAXN=2e5+51,inf=1e15;
    multiset<ll>st,gap;
    multiset<ll>::iterator it;
    ll n,qcnt,op,u,prv,nxt,mx,mn;
    ll x[MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline void erase(ll x)
    {
        gap.erase(gap.find(x));
    }
    inline ll query()
    {
        if(*gap.begin()>=1e12)
        {
            return 0;
        }
        it=st.begin(),mn=*(++it),it=st.end(),--it,mx=*(--it);
        return it=gap.end(),--it,--it,mx-mn-*(--it);
    }
    int main()
    {
        n=read(),qcnt=read(),st.insert(inf),st.insert(-inf);
        for(register int i=1;i<=n;i++)
        {
            st.insert(x[i]=read());
        }
        sort(x+1,x+n+1),x[0]=-inf,x[n+1]=inf;
        for(register int i=1;i<=n+1;i++)
        {
            gap.insert(x[i]-x[i-1]);
        }
        printf("%lld
    ",query());
        for(register int i=0;i<qcnt;i++)
        {
            op=read(),u=read();
            if(op==0)
            {
                it=st.find(u),prv=u-*(--it),it++,nxt=*(++it)-u;
                st.erase(u),erase(prv),erase(nxt),gap.insert(nxt+prv);
            }
            if(op==1)
            {
                it=st.upper_bound(u),nxt=*(it--),prv=*it,st.insert(u);
                erase(nxt-prv),gap.insert(nxt-u),gap.insert(u-prv);
            }
            if(*gap.begin()>=1e12)
            {
                puts("0");
                continue;
            }
            printf("%lld
    ",query());
        }
    }
    
  • 相关阅读:
    【SpringFramework】Spring 事务控制
    Mini 学生管理器
    方法的重写override,重载overload。
    方法封装,属性调用以及设置。
    判断hdfs文件是否存在
    模拟(删除/远程拷贝)当前一周的日志文件
    2.上传hdfs系统:将logs目录下的日志文件每隔十分钟上传一次 要求:上传后的文件名修为:2017111513xx.log_copy
    使用定时器:在logs目录,每两分钟产生一个文件
    五个节点的hadoop集群--主要配置文件
    hadoop集群配置文件与功能对应解析
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13726170.html
Copyright © 2011-2022 走看看