2020 Multi-University Training Contest 2---- HDU--6770、Dynamic Convex Hull (离线、分治)

题目连接

题面:
在这里插入图片描述
题意:
有一个四次函数的集合 f i ( x ) = ( x − a i ) 4 + b i f_i(x)=(x-a_i)^4+b_i fi(x)=(xai)4+bi

有以下三种操作
(1) 1 1 1 a a a b b b ,往集合中添加新的四次函数 f n + 1 = ( x − a ) 4 + b f_{n+1}=(x-a)^4+b fn+1=(xa)4+b,然后 n = n + 1 n=n+1 n=n+1
(2) 2 2 2 t t t ,从集合中删除 f t ( x ) f_t(x) ft(x)
(3) 3 3 3 x x x ,在当前集合中询问 f i ( x ) f_i(x) fi(x) 的最小值。

官方题解:
在这里插入图片描述

题解:
(1) 先考虑证明一下时间复杂度,相当于我们有 n l o g n nlogn nlogn 个点放在线段树上,每个点只能放在线段树的一个节点上,线段树的一个节点可以放多个点。然后我们对线段树的每个节点进行处理,每个节点处理的时间复杂度是 O ( c n t ∗ l o g ( c n t ) ) O(cnt*log (cnt)) O(cntlog(cnt)) 的, c n t cnt cnt 为线段树上当前节点上面的点数, ∑ c n t = n l o g n \sum cnt=nlogn cnt=nlogn,那么总的时间复杂度就是 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n) 的。

(2)我们离线所有操作序列,按照时间建立线段树,每个函数在时间轴上的存在部分一定是一个区间,在线段树上至多对应 l o g n logn logn 个区间,将函数在时间轴上的存在部分插入线段树。

对于每个询问,其在时间轴上对应一个点,在线段树上对应一个叶子节点,那么对其有贡献的四次函数 f f f,一定在线段树对应叶子节点到根这 l o g n logn logn 个节点上。我们将一个询问拆为 l o g n logn logn 个询问插入这些节点(最后再取个最小值即可)。

现在对于线段树的每个节点,有若干标记和若干询问。这是一个静态问题。下面考虑怎么在 n l o g n nlogn nlogn 的时间复杂度内处理线段树的一个节点。

对于每个询问 x x x ,分别找到 a i ≤ x a_i\le x aix x ≤ a i x\le a_i xai 的最优函数即可。

a i ≤ x a_i\le x aix 为例,考虑两个函数 ( x − a i ) 4 + b i (x-a_i)^4+b_i (xai)4+bi 以及 ( x − a j ) 4 + b j (x-a_j)^4+b_j (xaj)4+bj ,其中 a i ≤ a j a_i\le a_j aiaj

如果对于当前的 x k x_k xk 来说, ( x k − a i ) 4 + b i > = ( x k − a j ) 4 + b j (x_k-a_i)^4+b_i >= (x_k-a_j)^4+b_j (xkai)4+bi>=(xkaj)4+bj ,那么对于所有的 x p > = x k x_p>=x_k xp>=xk,上式均成立(两个四次函数开口向上,大小相同,只有对称轴和底端点不同)。
即如果 a i a_i ai 不是 x k x_k xk 的最优解,那么 a i a_i ai 不是 x p > = x k x_p>=x_k xp>=xk 的最优解。即 x p x_p xp 的最优解 a g a_g ag 一定 g > = j g>=j g>=j

如果对于当前的 x k x_k xk 来说, ( x k − a i ) 4 + b i < = ( x k − a j ) 4 + b j (x_k-a_i)^4+b_i <= (x_k-a_j)^4+b_j (xkai)4+bi<=(xkaj)4+bj ,那么对于所有的 x p < = x k x_p<=x_k xp<=xk,上式均成立(两个四次函数开口向上,大小相同,只有对称轴和底端点不同)。
即如果 a j a_j aj 不是 x k x_k xk 的最优解,那么 a j a_j aj 不是 x p < = x k x_p<=x_k xp<=xk 的最优解。即 x p x_p xp 的最优解 a g a_g ag 一定 g < = i g<=i g<=i

a i > = x a_i >=x ai>=x a i < = a j a_i<=a_j ai<=aj
如果对于当前的 x k x_k xk 来说, ( x k − a i ) 4 + b i < = ( x k − a j ) 4 + b j (x_k-a_i)^4+b_i <= (x_k-a_j)^4+b_j (xkai)4+bi<=(xkaj)4+bj ,那么对于所有的 x p < = x k x_p<=x_k xp<=xk,上式均成立(两个四次函数开口向上,大小相同,只有对称轴和底端点不同)。
即如果 a j a_j aj 不是 x k x_k xk 的最优解,那么 a j a_j aj 不是 x p < = x k x_p<=x_k xp<=xk 的最优解。即 x p x_p xp 的最优解 a g a_g ag 一定 g < = i g<=i g<=i

如果对于当前的 x k x_k xk 来说, ( x k − a i ) 4 + b i > = ( x k − a j ) 4 + b j (x_k-a_i)^4+b_i >= (x_k-a_j)^4+b_j (xkai)4+bi>=(xkaj)4+bj ,那么对于所有的 x p > = x k x_p>=x_k xp>=xk,上式均成立(两个四次函数开口向上,大小相同,只有对称轴和底端点不同)。
即如果 a i a_i ai 不是 x k x_k xk 的最优解,那么 a i a_i ai 不是 x p > = x k x_p>=x_k xp>=xk 的最优解。即 x p x_p xp 的最优解 a g a_g ag 一定 g > = j g>=j g>=j

我们将函数按照 a a a 从小到大排序,将询问按照 x x x 从小到大排序,则最优决策具有单调性,可以分治求解。分别求解 a i ≤ x a_i\le x aix x ≤ a i x\le a_i xai 即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<set>
#include<ctime>
#define ui unsigned int
#define ll long long
#define llu unsigned ll
#define ld long double
#define pr make_pair
#define pb push_back
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x)  (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
#define fhead(x) for(int i=head[(x)];i;i=nt[i])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
using namespace std;

const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const double alpha=0.75;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=100100;
const int maxm=100100;
const int maxp=100100;
const int up=1100;

struct func
{
    ll a,b;
    int l,r;
}f[maxn<<1];

bool cmp1(const func &a,const func &b)
{
    return a.a<b.a;
}

struct node
{
    ll x;
    int id;
}q[maxn];

bool cmp2(const node &a,const node &b)
{
    return a.x<b.x;
}

struct tree
{
    int l,r;
    vector<int>idf,idq;
}t[maxn<<2];

int idf[maxn<<1],idq[maxn];
ll ans[maxn];

void build(int l,int r,int cnt)
{
    t[cnt].l=l,t[cnt].r=r;
    t[cnt].idf.clear();
    t[cnt].idq.clear();
    if(l==r) return ;
    build(l,tmid,lc);
    build(tmid+1,r,rc);
}


void change(int l,int r,int cnt,int k,bool flag)
{
    if(l>r) return ;
    if(!flag) t[cnt].idq.pb(k);
    if(l<=t[cnt].l&&t[cnt].r<=r)
    {
        if(flag) t[cnt].idf.pb(k);
        return ;
    }
    if(l<=t[lc].r) change(l,r,lc,k,flag);
    if(r>=t[rc].l) change(l,r,rc,k,flag);
}

ll fi(ll x)
{
    return x*x*x*x;
}

//ai<=x
void so1(int ql,int qr,int fl,int fr)
{
    if(ql>qr||fl>fr) return ;
    int mid=(ql+qr)>>1,pos=fl;
    ll minn=lnf;
    for(int i=fl;i<=fr;i++)
    {
        if(f[idf[i]].a>q[idq[mid]].x) continue;
        if(fi(q[idq[mid]].x-f[idf[i]].a)+f[idf[i]].b<minn)
            minn=fi(q[idq[mid]].x-f[idf[i]].a)+f[idf[i]].b,pos=i;
    }
    ans[q[idq[mid]].id]=min(ans[q[idq[mid]].id],minn);
    so1(ql,mid-1,fl,pos);
    so1(mid+1,qr,pos,fr);
}

//ai>=x
void so2(int ql,int qr,int fl,int fr)
{
    if(ql>qr||fl>fr) return ;
    int mid=(ql+qr)>>1,pos=fr;
    ll minn=lnf;
    for(int i=fl;i<=fr;i++)
    {
        if(f[idf[i]].a<q[idq[mid]].x) continue;
        if(fi(q[idq[mid]].x-f[idf[i]].a)+f[idf[i]].b<minn)
            minn=fi(q[idq[mid]].x-f[idf[i]].a)+f[idf[i]].b,pos=i;
    }
    ans[q[idq[mid]].id]=min(ans[q[idq[mid]].id],minn);
    so2(ql,mid-1,fl,pos);
    so2(mid+1,qr,pos,fr);
}

void dfs(int cnt)
{
    if(t[cnt].idf.size()>0&&t[cnt].idq.size()>0)
    {
        for(int i=0;i<t[cnt].idf.size();i++)
            idf[i+1]=t[cnt].idf[i];
        for(int i=0;i<t[cnt].idq.size();i++)
            idq[i+1]=t[cnt].idq[i];
        so1(1,t[cnt].idq.size(),1,t[cnt].idf.size());
        so2(1,t[cnt].idq.size(),1,t[cnt].idf.size());
    }
    if(t[cnt].l==t[cnt].r)
    {
        if(t[cnt].idq.size()!=0)
            printf("%lld\n",ans[q[t[cnt].idq[0]].id]==lnf?-1:ans[q[t[cnt].idq[0]].id]);
        return ;
    }
    dfs(lc);
    dfs(rc);
}

int main(void)
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        int n,m,op,t;
        scanf("%d%d",&n,&m);
        build(1,m,1);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld",&f[i].a,&f[i].b);
            f[i].l=1,f[i].r=m;
        }
        int cntf=n,cntq=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&op);
            ans[i]=lnf;
            if(op==1)
            {
                ++cntf;
                scanf("%lld%lld",&f[cntf].a,&f[cntf].b);
                f[cntf].l=i,f[cntf].r=m;
            }
            else if(op==2)
            {
                scanf("%d",&t);
                f[t].r=i-1;
            }
            else if(op==3)
            {
                ++cntq;
                scanf("%lld",&q[cntq].x);
                q[cntq].id=i;
            }
        }

        sort(f+1,f+cntf+1,cmp1);
        sort(q+1,q+cntq+1,cmp2);
        for(int i=1;i<=cntf;i++)
            change(f[i].l,f[i].r,1,i,true);
        for(int i=1;i<=cntq;i++)
            change(q[i].id,q[i].id,1,i,false);
        dfs(1);
    }
    return 0;
}



©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页