ACM-ICPC 2018 南京赛区网络预赛 G. Lpl and Energy-saving Lamps (线段树)

https://nanti.jisuanke.com/t/30996 

 

题意:

有n个房间,里面分别有ai盏灯需要更换,Lpl每月都会买m盏灯,如果刚好能更换一个房间就会把灯都更换掉,如果不能就会继续找下一个房间看是否能全部更换,剩余的灯就会被留到下个月使用,最后输出她每月最多能更换的房间数和所剩余的灯的数量。

 

思路:

直接线段树找到最左边小于一个数的位置,然后把可以换的更新成inf。

 

代码:

#include
using namespace std;
#define ll long long
const int maxn=1e5+10;
const int inf=0x7fffffff;
int minn[maxn<<2];
int x[maxn],y[maxn];
int a[maxn];
int w[maxn];
void update(int pos,int val,int l,int r,int rt)
{
    if(l==r)
    {
        minn[rt]=val;
        return;
    }
    int mid=(l+r)/2;
    if(pos<=mid)update(pos,val,l,mid,rt*2);
    else update(pos,val,mid+1,r,rt*2+1);
    minn[rt]=min(minn[rt*2],minn[rt*2+1]);
}
int query(int val,int l,int r,int rt)
{
    if(l==r)return l;
    int mid=(l+r)/2;
    if(minn[rt*2]<=val)return query(val,l,mid,rt*2);
    if(minn[rt*2+1]<=val)return query(val,mid+1,r,rt*2+1);
    return -1;
}
int main()
{
    int m,n;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&w[i]),update(i,w[i],1,n,1);
    int q;
    scanf("%d",&q);
    int mx=0;
    for(int i=1;i<=q;i++)
        scanf("%d",&a[i]),mx=max(a[i],mx);
    int ans=0;
    int js=0;
    for(int i=1;i<=mx;i++)
    {
        ans+=m;
        while(1)
        {
            int id=query(ans,1,n,1);
            if(id!=-1)
            {
                js++;
                ans-=w[id];
                update(id,inf,1,n,1);
                x[i]=js;
                y[i]=ans;
            }
            else
            {
                 x[i]=js;
                y[i]=ans;
                break;
            }
        }
    }
    for(int i = 1;i <= q;i++)
        printf("%d %d\n",x[a[i]],y[a[i]]);

}

 

你可能感兴趣的:(线段树)