Loading

题解 【CF1418D Trash Problem】

\(\Large\texttt{CF1418D}\)

前言:

强烈谴责这套 \(\texttt{div.2}\) 的翻译(前面ABC更偏),做这套题目时想崩掉,还是读英文题面好。/cy

题意

可以参考参考神 \(\texttt{Karry5307}\) 的翻译,十分得清晰, 这里不多做赘述。

思路

其实思路十分显然,对于两颗木桩坐标为 \(x_1\) , \(x_2\)产生的总花费,分三种情况讨论:

  • 显然左边的木桩左边的点全到左边的木桩,花费为 \(x1-min_x\)

  • 显然右边的木桩右边的点全到右边的木桩,花费为 \(max_x-x_2\)

  • 中间的点离哪棵木桩近就去哪,但是有一点十分重要,中间的木桩花费的最优情况肯定是分成两部分,左边到左边的木桩,右边到右边的木桩,令这两部分零界的点分别为 \(x_3\) , \(x_4\),产生的花费为 \((x_3-x_1)+(x_2-x_4)\)

花费全加起来,你会恍然大悟地发现,花费为 \((max_x-min_x)-(x_3-x_2)\) ( \(x_2\)\(x_3\) 之间没有其它点)。

在每个状态下,\(max_x\)\(min_x\) 是一定的,要让花费最小,问题就变成了动态维护区间中任意两点之间最远的距离

题解区一群大佬用了蒟蒻我不会的科技轻松A掉了,于是蒟蒻我只好用大码量的线段树解决(vp时出现了一个小错误导致没有绝杀QwQ) 。

线段树维护三个值,区间内最长的两点间的距离,区间内最左边的点的位置,区间内最右边的点的位置。

你会发现顺便把动态维护最大值和最小值给做掉了,但是我原本还弄了个查询操作QwQ

具体的 \(up\) 操作请见代码

代码

\(4.99s\) 最优解第一

#include <bits/stdc++.h>
using namespace std;

#define ls n << 1
#define rs n << 1 | 1
const int N = 2e5;
inline int read()
{
    register int s = 0;
    register bool neg = 0;
    register char c = getchar();
    for (; c < '0' || c > '9'; c = getchar())
        neg |= (c == '-');
    for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar())
        ;
    return (neg ? -s : s);
}

int a,b,q[N+10],p[N+10],top;
bool t[N+10];
struct node {
    int l,r,lmx,rmx,sum;
}s[N*4+10];
struct ask {
    int opt,x;
}ask[N+10];

inline void up(int n) {
    s[n].lmx=((s[ls].lmx==-1)?s[rs].lmx:s[ls].lmx);//区间内端点只有一个的时候将左端点和右端点赋值一样,方便操作。
    s[n].rmx=((s[rs].rmx==-1)?s[ls].rmx:s[rs].rmx);
    s[n].sum=max(max(s[ls].sum,s[rs].sum),s[ls].rmx!=-1&&s[rs].lmx!=-1?s[rs].lmx-s[ls].rmx:0);//注意左区间的右端点到有区间的左端点也要被统计在内
}

inline void build(int n,int l,int r) {
    s[n].l=l;
    s[n].r=r;
    s[n].sum=0;
    s[n].lmx=-1;
    s[n].rmx=-1;
    if(l==r) {
        if(t[l]) s[n].lmx=s[n].rmx=p[l];
        return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    up(n);
}

inline void insert(int n,int k) {
    if(s[n].l==s[n].r) {
        s[n].lmx=s[n].rmx=p[k];
        return;
    }
    int mid=(s[n].l+s[n].r)>>1;
    if(k<=mid) insert(ls,k);
    else insert(rs,k);
    up(n);
}

inline void del(int n,int k) {
    if(s[n].l==s[n].r) {
        s[n].lmx=s[n].rmx=-1;
        return;
    }
    int mid=(s[n].l+s[n].r)>>1;
    if(k<=mid) del(ls,k);
    else del(rs,k);
    up(n);
}

signed main()
{
    // freopen("in1.in","r",stdin);
    a=read();
    b=read();
    top=0;
    for(int i=1;i<=a;i++){
        q[i]=p[++top]=read();
    }
    for(int i=1;i<=b;i++) {
        ask[i].opt=read();
        ask[i].x=p[++top]=read();
    }
    sort(p+1,p+top+1);
    top=unique(p+1,p+top+1)-p-1;
    for(int i=1;i<=a;i++) t[lower_bound(p+1,p+top+1,q[i])-p]=1;
    build(1,1,top);
    printf("%d\n",s[1].rmx-s[1].lmx-s[1].sum);
    for(int i=1;i<=b;i++) {
        if(ask[i].opt==1)
            insert(1,lower_bound(p+1,p+top+1,ask[i].x)-p);
        else
            del(1,lower_bound(p+1,p+top+1,ask[i].x)-p);
        printf("%d\n",s[1].rmx-s[1].lmx-s[1].sum);
    }
    return 0;
}

十分遗憾的一题QwQ

posted @ 2020-10-30 21:08  RedreamMer  阅读(105)  评论(0编辑  收藏  举报