[IOI2018]meetings会议——分治+线段树

题目链接:

[IOI2018]meetings

还是按照编号都从1开始讲。

可以发现对于一个询问如果确定了开会地址那么答案只和每个点到开会点区间最大值有关。

而题目又没有强制在线,我们可以按区间最大值来分治。

我们设对于区间[l,r]的答案是ans(l,r),区间中的最大值位于mid处(即h[mid]是区间最大值)。

那么显然答案选定的开会点一定在mid的左侧或右侧,ans(l,r)=min{ans(l,mid-1)+h[mid]*(r-mid+1),ans(mid+1,r)+h[mid]*(mid-l+1)}。

即如果开会点在mid左边那么mid及右边所有点到开会点的代价都是h[mid],如果开会点在mid右边那么mid及左边所有点到开会点的代价都是h[mid]。

因此,ans(l,r)要由ans(l,mid-1)与ans(mid+1,r)合并而来。

那么我们可以确定一个大致思路:找出当前区间最大值位置然后分治左右区间,在得出左右区间的答案之后再处理询问区间最大值是当前区间最大值的询问,然后再递归回上一些层。

 区间最大值很好求,用ST表维护一下即可,那么对于每个区间的ans怎么维护?

对于左端点为l的区间难道要同时维护出ans(l,l),ans(l,l+1),ans(l,l+2)……吗?

显然并不需要,我们发现对于每一次递归的区间[l,r],需要用到左端点为l的ans只有ans(l,mid-1)和ans(l,r)。

其中前者对应处理当前层询问前递归合并上来的答案,后者则对应处理完当前层询问后需要递归合并上去的答案。

也就是说对于一个点x,在同一时刻只需要维护它作为一个区间左端点和右端点时这两个答案。

那么我们就可以用线段树来实现,对于线段树上每个叶子结点维护lm和rm两个信息,分别表示这个点是区间左/右端点时的区间答案。

因为我们不知道对于当前递归区间[l,r]递归回上一层时是在上一层最大值的左边还是右面,所以要用两棵线段树分别维护这两种情况。

总结一下大体思路:对于当前区间找到区间最大值位置并递归左右子区间,回溯时处理当前区间需要处理的询问,对于每个ans(x,mid-1)(l<=x<=mid-1)更新为ans(x,r);对于每个ans(mid+1,x)(mid+1<=x<=r)更新为ans(l,x)。

因为每个点被当做区间最大值一次且每个询问被处理一次,所以时间复杂度是O((n+q)logn)。

如果还是不太明白可以看代码的具体实现。

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long 
using namespace std;
int n,q;
int h[750010];
int ql[750010];
int qr[750010];
ll res[750010];
int f[750010][21];
int g[750010][21];
int ln[750010];
vector<int>pos[750010];
struct miku
{
    ll lm[4000010];
    ll rm[4000010];
    ll k[4000010];
    ll b[4000010];
    int a[4000010];
    void cover(int rt)
    {
        a[rt]=1;
        lm[rt]=rm[rt]=k[rt]=b[rt]=0;
    }
    void add(int rt,int l,int r,ll K,ll B)
    {
        k[rt]+=K;
        b[rt]+=B;
        lm[rt]+=K*l+B;
        rm[rt]+=K*r+B;
    }
    void pushup(int rt)
    {
        lm[rt]=lm[rt<<1];
        rm[rt]=rm[rt<<1|1];
    }
    void pushdown(int rt,int l,int r)
    {
        int mid=(l+r)>>1;
        if(a[rt])
        {
            a[rt]=0;
            cover(rt<<1);
            cover(rt<<1|1);
        }
        if(k[rt]||b[rt])
        {
            add(rt<<1,l,mid,k[rt],b[rt]);
            add(rt<<1|1,mid+1,r,k[rt],b[rt]);
            k[rt]=b[rt]=0;
        }
    }
    void change(int rt,int l,int r,int L,int R,ll val)
    {
        if(L<=l&&r<=R)
        {
            add(rt,l,r,0,val);
            return ;
        }
        int mid=(l+r)>>1;
        pushdown(rt,l,r);
        if(L<=mid)
        {
            change(rt<<1,l,mid,L,R,val);
        }
        if(R>mid)
        {
            change(rt<<1|1,mid+1,r,L,R,val);
        }
        pushup(rt);
    }
    void merge(int rt,int l,int r,int L,int R,ll K,ll B)
    {
        if(L<=l&&r<=R)
        {
            ll LV=K*l+B;
            ll RV=K*r+B;
            if(LV>=lm[rt]&&RV>=rm[rt])
            {
                return ;
            }
            if(LV<=lm[rt]&&RV<=rm[rt])
            {
                cover(rt);
                add(rt,l,r,K,B);
                return ;
            }
        }
        pushdown(rt,l,r);
        int mid=(l+r)>>1;
        if(L<=mid)
        {
            merge(rt<<1,l,mid,L,R,K,B);
        }
        if(R>mid)
        {
            merge(rt<<1|1,mid+1,r,L,R,K,B);
        }
        pushup(rt);
    }
    ll query_left(int rt,int l,int r,int x)
    {
        if(l==r)
        {
            return lm[rt];
        }
        pushdown(rt,l,r);
        int mid=(l+r)>>1;
        if(x<=mid)
        {
            return query_left(rt<<1,l,mid,x);
        }
        else
        {
            return query_left(rt<<1|1,mid+1,r,x);
        }
    }
    ll query_right(int rt,int l,int r,int x)
    {
        if(l==r)
        {
            return rm[rt];
        }
        pushdown(rt,l,r);
        int mid=(l+r)>>1;
        if(x<=mid)
        {
            return query_right(rt<<1,l,mid,x);
        }
        else
        {
            return query_right(rt<<1|1,mid+1,r,x);
        }
    }
}s,t;
int cmp(int l,int r)
{
    int len=ln[r-l+1];
    if(f[l][len]>=f[r-(1<<len)+1][len])
    {
        return g[l][len];
    }
    else
    {
        return g[r-(1<<len)+1][len];
    }
}
void solve(int l,int r)
{
    if(l>r)
    {
        return ;
    }
    int mid=cmp(l,r);
    solve(l,mid-1);
    solve(mid+1,r);
    int len=pos[mid].size();
    for(int i=0;i<len;i++)
    {   
        int now=pos[mid][i];
        res[now]=1ll*h[mid]*(qr[now]-ql[now]+1);
        if(ql[now]<mid)
        {
            res[now]=min(res[now],s.query_left(1,1,n,ql[now])+1ll*h[mid]*(qr[now]-mid+1));
        }
        if(qr[now]>mid)
        {
            res[now]=min(res[now],t.query_right(1,1,n,qr[now])+1ll*h[mid]*(mid-ql[now]+1));
        }
    }
    ll sx=h[mid];
    ll tx=h[mid];
    if(l<mid)
    {
        tx+=t.query_right(1,1,n,mid-1);
    }
    if(r>mid)
    {
        sx+=s.query_left(1,1,n,mid+1);
    }
    s.change(1,1,n,mid,mid,sx);
    t.change(1,1,n,mid,mid,tx);
    if(l<mid)
    {
        s.change(1,1,n,l,mid-1,1ll*h[mid]*(r-mid+1));
        s.merge(1,1,n,l,mid-1,-1ll*h[mid],sx+1ll*mid*h[mid]);
    }
    if(r>mid)
    {
        t.change(1,1,n,mid+1,r,1ll*h[mid]*(mid-l+1));
        t.merge(1,1,n,mid+1,r,1ll*h[mid],tx-1ll*mid*h[mid]);
    }
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&h[i]);
        f[i][0]=h[i];
        g[i][0]=i;
    }
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&ql[i],&qr[i]);
        ql[i]++;
        qr[i]++;
    }
    for(int i=2;i<=n;i++)
    {
        ln[i]=ln[i>>1]+1;
    }
    for(int j=1;j<=20;j++)
    {
        for(int i=1;i<=n;i++)
        {
            if(i+(1<<j)-1>n)
            {
                break;
            }
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
            if(f[i][j]==f[i][j-1])
            {
                g[i][j]=g[i][j-1];
            }
            else
            {
                g[i][j]=g[i+(1<<(j-1))][j-1];
            }
        }
    }
    for(int i=1;i<=q;i++)
    {
        pos[cmp(ql[i],qr[i])].push_back(i);
    }
    solve(1,n);
    for(int i=1;i<=q;i++)
    {
        printf("%lld\n",res[i]);
    }
}

猜你喜欢

转载自www.cnblogs.com/Khada-Jhin/p/10017454.html
今日推荐