CodeFoces 500E - New Year Domino

本文介绍了一种离线算法来解决特定情况下牌子摆放的问题。通过预处理和分类讨论,实现了从右到左枚举并更新状态的过程,最终得到了最小花费的解决方案。

首先将所有的牌子放倒,那么花费就是牌子L和牌子R之间的空隙长度。

有一种特殊情况,存在牌子P(p < L)特别长,以至于影响了L,R之间的空隙长度。

所以我只想到了一种离线算法。

cov[i] 记录覆盖牌子i的编号。

dis[i] 记录推到牌子i所能到达的最远距离。

cost[i]记录L= i,R = n 时的最小花费。

首先预处理出dis[i],cost[i]。

然后将询问按L排序,然后从右到左枚举牌子。

枚举时不断更新cov[i],然后分类讨论得到答案。

弱用了三棵线段树才水过去,应该存在更简洁的方法。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <ctime>
#include <iomanip>

#pragma comment(linker,"/STACK:1024000000");
#define EPS (1e-6)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 1000000007
#define mod 1000000007

/** I/O Accelerator Interface .. **/
#define g (c=getchar())
#define d isdigit(g)
#define p x=x*10+c-'0'
#define n x=x*10+'0'-c
#define pp l/=10,p
#define nn l/=10,n
template<class T> inline T& RD(T &x)
{
    char c;
    while(!d);
    x=c-'0';
    while(d)p;
    return x;
}
template<class T> inline T& RDD(T &x)
{
    char c;
    while(g,c!='-'&&!isdigit(c));
    if (c=='-')
    {
        x='0'-g;
        while(d)n;
    }
    else
    {
        x=c-'0';
        while(d)p;
    }
    return x;
}
inline double& RF(double &x)      //scanf("%lf", &x);
{
    char c;
    while(g,c!='-'&&c!='.'&&!isdigit(c));
    if(c=='-')if(g=='.')
        {
            x=0;
            double l=1;
            while(d)nn;
            x*=l;
        }
        else
        {
            x='0'-c;
            while(d)n;
            if(c=='.')
            {
                double l=1;
                while(d)nn;
                x*=l;
            }
        }
    else if(c=='.')
    {
        x=0;
        double l=1;
        while(d)pp;
        x*=l;
    }
    else
    {
        x=c-'0';
        while(d)p;
        if(c=='.')
        {
            double l=1;
            while(d)pp;
            x*=l;
        }
    }
    return x;
}
#undef nn
#undef pp
#undef n
#undef p
#undef d
#undef g
using namespace std;

struct N
{
    int l,p;
}st[200010];

int far[200010];

int Max[800100];

int dis[200010];

int Val[800100];

LL cost[200100];

int Init(int site,int l,int r)
{
    if(l == r)
        return Val[site] = st[l].l+st[l].p;

    int mid = (l+r)>>1;

    return Val[site] = max(Init(site<<1,l,mid),Init(site<<1|1,mid+1,r));
}

void Update(int site,int l,int r,int x,int d)
{
    if(l == r)
    {
        Max[site] = max(Max[site],d);
        return ;
    }

    int mid = (l+r)>>1;

    if(x <= mid)
        Update(site<<1,l,mid,x,d);
    else
        Update(site<<1|1,mid+1,r,x,d);
    Max[site] = max(Max[site<<1],Max[site<<1|1]);
}

int Query(int site,int L,int R,int l,int r)
{
    if(L == l && R == r)
        return Max[site];

    int mid = (L+R)>>1;

    if(r <= mid)
        return Query(site<<1,L,mid,l,r);
    if(mid < l)
        return Query(site<<1|1,mid+1,R,l,r);

    return max(Query(site<<1,L,mid,l,mid),Query(site<<1|1,mid+1,R,mid+1,r));
}

int Query1(int site,int L,int R,int l,int r)
{
    if(L == l && R == r)
        return Val[site];

    int mid = (L+R)>>1;

    if(r <= mid)
        return Query1(site<<1,L,mid,l,r);
    if(mid < l)
        return Query1(site<<1|1,mid+1,R,l,r);

    return max(Query1(site<<1,L,mid,l,mid),Query1(site<<1|1,mid+1,R,mid+1,r));
}

int BS(LL x,int s,int e)
{
    int mid , site = 0;

    while(s <= e)
    {
        mid = (s+e)>>1;

        if(st[mid].p <= x)
            s = mid+1,site = mid;
        else
            e = mid-1;
    }

    return site;
}

void Cal(int x,int n)
{
    int site = BS(st[x].l+st[x].p,x,n);

    if(site == x)
        far[x] = x;
    else if(site == n)
        far[x] = n;
    else
        far[x] = Query(1,1,n,x,site);

    Update(1,1,n,x,far[x]);
}

int FindSite(int x,int l,int r)
{
    int mid,site = r;

    while(l <= r)
    {
        mid = (l+r)>>1;
        if(far[mid] == x)
            site = min(site,mid);
        if(far[mid] < x)
            l = mid+1;
        else
            r = mid-1;
    }
    return site;
}

struct Qu
{
    int l,r,site;
    LL anw;
}qu[200010];


bool cmp1(Qu q1,Qu q2)
{
    return q1.l < q2.l;
}

bool cmp2(Qu q1,Qu q2)
{
    return q1.site < q2.site;
}

struct Co
{
    int id;
    bool mark;
}cov[800100];

void InitCo(int site,int l,int r)
{
    if(l == r)
    {
        cov[site].id = l,cov[site].mark = true;
        return ;
    }
    int mid =(l+r)>>1;

    InitCo(site<<1,l,mid);
    InitCo(site<<1|1,mid+1,r);

    if(cov[site<<1].id == cov[site<<1|1].id && cov[site<<1].id != -1)
        cov[site].mark = true,cov[site].id = cov[site<<1].id;
    else
        cov[site].mark = false,cov[site].id = -1;
}

void UpdateCo(int site,int L,int R,int l,int r,int id)
{
    if(L == l && R == r)
    {
        cov[site].mark = true;
        cov[site].id = id;
        return ;
    }

    int mid = (L+R)>>1;

    if(cov[site].mark == true)
    {
        cov[site<<1] = cov[site];
        cov[site<<1|1] = cov[site];

        cov[site].mark = false;
        cov[site].id = -1;
    }

    if(r <= mid)
        UpdateCo(site<<1,L,mid,l,r,id);
    else if(mid < l)
        UpdateCo(site<<1|1,mid+1,R,l,r,id);
    else
    {
        UpdateCo(site<<1,L,mid,l,mid,id);
        UpdateCo(site<<1|1,mid+1,R,mid+1,r,id);
    }

    if(cov[site<<1].id == cov[site<<1|1].id && cov[site<<1].id != -1)
        cov[site].mark = true,cov[site].id = cov[site<<1].id;
    else
        cov[site].mark = false,cov[site].id = -1;
}

int QueryCo(int site,int L,int R,int x)
{
    if(cov[site].mark )
        return cov[site].id;

    int mid = (L+R)>>1;

    if(x <= mid)
        return QueryCo(site<<1,L,mid,x);
    else
        return QueryCo(site<<1|1,mid+1,R,x);
}

int main()
{
    int n,i,j,q;

    scanf("%d",&n);

    for(i = 1;i <= n; ++i)
        scanf("%d %d",&st[i].p,&st[i].l);

    memset(Max,0,sizeof(Max));

    Update(1,1,n,n,n);

    for(far[n] = n,i = n-1; i >= 1; --i)
        Cal(i,n);

    Init(1,1,n);

    for(i = 1;i <= n; ++i)
        dis[i] = Query1(1,1,n,i,far[i]);

    for(cost[n] = 0,i = n-1;i >= 1; --i)
    {
        if(far[i] == n)
            cost[i] = 0;
        else
            cost[i] = cost[far[i]+1] + st[far[i]+1].p - dis[i];
    }

    scanf("%d",&q);

    int site;

    for(i = 1;i <= q; ++i)
    {
        scanf("%d %d",&qu[i].l,&qu[i].r);
        qu[i].site = i;
    }

    sort(qu+1,qu+q+1,cmp1);

    InitCo(1,1,n);

    for(j = q,i = n;i >= 1; --i)
    {
        UpdateCo(1,1,n,i,far[i],i);
     
        while(j >= 1 && qu[j].l == i)
        {
            if(far[i] >= qu[j].r)
                qu[j].anw = 0;
            else
            {
                site = QueryCo(1,1,n,qu[j].r);
                if(far[i] >= site)
                    qu[j].anw = 0;
                else
                    qu[j].anw = cost[i] - cost[site];
            }
            j--;
        }
    }

    sort(qu+1,qu+q+1,cmp2);

    for(i = 1;i <= q; ++i)
    {
        printf("%I64d\n",qu[i].anw);
    }


    return 0;
}

(1)普通用户端(全平台) 音乐播放核心体验: 个性化首页:基于 “听歌历史 + 收藏偏好” 展示 “推荐歌单(每日 30 首)、新歌速递、相似曲风推荐”,支持按 “场景(通勤 / 学习 / 运动)” 切换推荐维度。 播放页功能:支持 “无损音质切换、倍速播放(0.5x-2.0x)、定时关闭、歌词逐句滚动”,提供 “沉浸式全屏模式”(隐藏冗余控件,突出歌词与专辑封面)。 多端同步:自动同步 “播放进度、收藏列表、歌单” 至所有登录设备(如手机暂停后,电脑端打开可继续播放)。 音乐发现与管理: 智能搜索:支持 “歌曲名 / 歌手 / 歌词片段” 搜索,提供 “模糊匹配(如输入‘晴天’联想‘周杰伦 - 晴天’)、热门搜索词推荐”,结果按 “热度 / 匹配度” 排序。 歌单管理:创建 “公开 / 私有 / 加密” 歌单,支持 “批量添加歌曲、拖拽排序、一键分享到社交平台”,系统自动生成 “歌单封面(基于歌曲风格配色)”。 音乐分类浏览:按 “曲风(流行 / 摇滚 / 古典)、语言(国语 / 英语 / 日语)、年代(80 后经典 / 2023 新歌)” 分层浏览,每个分类页展示 “TOP50 榜单”。 社交互动功能: 动态广场:查看 “关注的用户 / 音乐人发布的动态(如‘分享新歌感受’)、好友正在听的歌曲”,支持 “点赞 / 评论 / 转发”,可直接点击动态中的歌曲播放。 听歌排行:个人页展示 “本周听歌 TOP10、累计听歌时长”,平台定期生成 “全球 / 好友榜”(如 “好友中你本周听歌时长排名第 3”)。 音乐圈:加入 “特定曲风圈子(如‘古典音乐爱好者’)”,参与 “话题讨论(如‘你心中最经典的钢琴曲’)、线上歌单共创”。 (2)音乐人端(创作者中心) 作品管理: 音乐上传:支持 “无损音频(FLAC/WAV)+ 歌词文件(LRC)+ 专辑封面” 上传,填写 “歌曲信息
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值