bzoj 1293: [SCOI2009]生日礼物【单调队列】

一开始用了复杂度看起来对实则常数巨大的线段树+hash……后来发现队列就行……

把珠子按位置排序,然后用队列维护一段,枚举右端点更新答案即可

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1000005,inf=2147483647;
int n,m,s[65],ans=inf,tot,sum,l=1,r;
struct qwe
{
    int k,p;
    qwe(int K=0,int P=0)
    {
        k=K,p=P;
    }
}a[N],q[N];
bool cmp(const qwe &a,const qwe &b)
{
    return a.p<b.p;
}
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
        for(int t=read();t>=1;t--)
            a[++tot]=qwe(i,read());
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        q[++r]=a[i];
        if(++s[q[r].k]==1)
            sum++;
        while(sum==m)
        {
            ans=min(ans,q[r].p-q[l].p);
            s[q[l].k]--;
            if(s[q[l].k]==0)
                sum--;
            l++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

极蠢线段树

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
const int N=1000005;
int n,m,g[N],tot,rl[N],has,ans=2e9,mn=0;
vector<int>a[65],b[N];
map<int,int>mp;
struct xds
{
    int l,r,mn;
}t[505];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void build(int ro,int l,int r)
{
    t[ro].l=l,t[ro].r=r;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(ro<<1,l,mid);
    build(ro<<1|1,mid+1,r);
}
void update(int ro,int p,int v)
{
    if(t[ro].l==t[ro].r)
    {
        t[ro].mn=v;
        return;
    }
    int mid=(t[ro].l+t[ro].r)>>1;
    if(p<=mid)
        update(ro<<1,p,v);
    else
        update(ro<<1|1,p,v);
    t[ro].mn=min(t[ro<<1].mn,t[ro<<1|1].mn);
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        for(int j=read();j>=1;j--)
        {
            g[++tot]=read();
            a[i].push_back(g[tot]);
        }
        mn=max(mn,a[i][0]);
    }
    sort(g+1,g+1+tot);
    for(int i=1;i<=tot;i++)
        if(i==1||g[i]!=g[i-1])
            mp[g[i]]=++has,rl[has]=g[i];
    for(int i=1;i<=m;i++)
        for(int j=0,len=a[i].size();j<len;j++)
            b[mp[a[i][j]]].push_back(i);
    build(1,1,m);
    for(int i=1;i<=has;i++)
        if(rl[i]>=mn)
        {
            for(int j=0,len=b[i].size();j<len;j++)
                update(1,b[i][j],rl[i]);
            ans=min(ans,rl[i]-t[1].mn);
        }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/9737620.html

时间: 2024-10-11 12:59:52

bzoj 1293: [SCOI2009]生日礼物【单调队列】的相关文章

BZOJ 1293: [SCOI2009]生日礼物 贪心

1293: [SCOI2009]生日礼物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2513  Solved: 1370[Submit][Status][Discuss] Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上. 小布生日快到了,于是小西打算剪一段彩带送给小

bzoj 1293: [SCOI2009]生日礼物

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1559  Solved: 848[Submit][Status][Discuss] Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上. 小布生日快到了,于是小西打算剪一段彩带送给小布.为了让礼物彩带足够漂亮,小西希望这一段彩

BZOJ 1293 SCOI2009 生日礼物 堆

题目大意:给定一个数轴上n个点,每个点有一种颜色,一共k种颜色,求一个最短的区间,包含所有k种颜色 卡了一段时间0.0 一开始想二分答案啥的 后来发现数据范围太大写不了0.0 后来去找题解才发现尼玛真巧妙 维护一个堆 将每种颜色的第一个珠子加入堆 然后不断把最左侧的珠子取出,加入该种颜色的下一个 同时更新ans 果然这么大数据范围还是要用堆这种常数小的数据结构啊0.0 我手写了堆却开了STL的queue 0.0 不要说我有病我只是不习惯STL的堆罢了 #include<queue> #incl

1293: [SCOI2009]生日礼物

1293: [SCOI2009]生日礼物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1096  Solved: 584[Submit][Status] Description 小西有一条很长的彩带,彩带上挂着各式各样的彩珠.已知彩珠有N个,分为K种.简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置).某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上. 小布生日快到了,于是小西打算剪一段彩带送给小布.为了让礼物彩带足

BZOJ 1855 股票交易(单调队列优化DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1855 题意:最近lxhgww又迷上了投资股票, 通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每 个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BS

BZOJ 1012 线段树||单调队列

非常裸的线段树  || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件. 线段树 #include "stdio.h" #include "string.h" struct node { int l,r,Max; }data[800010]; int Max(int a,int b) { if (a<b) return b; els

BZOJ 2424 订货(贪心+单调队列)

怎么题解都是用费用流做的啊...用单调队列多优美啊. 题意:某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付存贮费用m,假定第一月月初的库存量为零,第n月月底的库存量也为零,问如何安排这n个月订购计划,才能使成本最低?每月月初订购,订购后产品立即到货,进库并供应市场,于当月被售掉则不必付存贮费.假设仓库容量为S. 首先这道题和经典的汽车加油问题差不多,那道题可以用单调队列做,然而这道题也是可以的. 此题唯一的难点在于存储费用m,也

BZOJ 2276 Poi2011 Temperature 单调队列

题目大意:给定一个序列,每个元素的大小有一个取值范围,求一段区间满足区间内元素可能单调不降 对L维护一个单调不增的单调队列,一旦新插入的R值比队头的L值小就把队头弹掉 这样可以保证单调队列中的元素是合法的极大子区间 然后更新答案就行了 乱写读入优化害死人啊QwQ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 1001001 usi

BZOJ 1855 [Scoi2010]股票交易 单调队列优化DP

题意:链接 方法:单调队列优化DP 解析:噢又是一道情况很多的题,然而三种更新我又落下一种导致样例不过,后来看题解才恍然- -最SB的一种更新居然忘了. 状态好想f[i][j]代表前i天有j双袜子时的最大利润. 三种更新: 第一种:f[i][j]=max(f[i][j],f[i?1][j]):(然而我忘了这一种) 第二种:买入f[i][j]=max(f[i][j],f[i?w?1][k]?(j?k)?a[i].ap)(k>=j?a[i].as); 第三种:卖出f[i][j]=max(f[i][j