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

题目链接https://nanti.jisuanke.com/t/30996

 

中文题目

在喝茶的过程中,公主,除其他外,问为什么这样一个善良可爱的龙在城堡里被监禁Lpl?龙神秘地笑了笑,回答说这是个大秘密。暂停后,龙补充道:

- 我们有合同。租赁协议。他总是一整天都在工作。他喜欢沉默。除此之外,住在城堡还有更多的优势。比如说,很容易证明未接来电的合理性:电话铃声无法从手机离开的城堡的另一侧到达。因此,监禁只是一个故事。实际上,他思考一切。他很聪明。例如,他开始用整个城堡中的节能灯替换白炽灯......

Lpl选择了一种节能灯模型并开始更换,如下所述。他为城堡中的所有房间编号并计算每个房间需要更换多少盏灯。

在每个月初,Lpl购买m个节能灯替换房间里的灯泡根据他的名单。他从名单上的第一个房间开始。如果这个房间的灯还没有更换,Lpl有足够的节能灯来更换所有的灯,那么他将取代所有的灯并从列表中取出房间。否则,他只是跳过它并检查他列表中的下一个房间。这个过程一直重复,直到他没有节能灯或他已经检查了他的清单中的所有房间。如果他检查了清单上的所有房间后仍然有一些节能灯,那么他将在下个月保存其余的节能灯。

一旦完成所有工作,他就会停止购买新灯具。它们质量非常高,周期长。

您的任务是在给定的月份和房间描述中计算旧灯具将用节能灯替换的房间数量以及每个月底将保留多少节能灯。

输入

每个输入都包含一个测试用例。

第一行包含整数n和m

 

-房间在城堡的数量和节能灯的数量,这LPL购买每月。

第二行包含n整数k1,k2,...,kn

- 城堡房间的灯数。位置数量Ĵj是灯的数量Ĵ第j个房间。房间号码根据Lpl的清单给出。

第三行包含一个整数 q(1<=q<=100000)-的查询的数量。

第四行包含q整数d1,d2,...,dq

- 形成查询的月数。

月份以编号开头1;在第一个月初,Lpl购买了第一批m个节能灯。

产量

打印q行。

线p包含两个整数 - 房间数量,其中所有旧灯泡已经更换,剩下的节能灯数量到最后dp月。

暗示

样本说明:

在第一个月,他买了4个节能灯他取代了他列表中的第一个房间并将其移除。然后他有1个节能灯,然后跳过所有房间。所以,第一个月的答案是1,1 ------ 1个房间的灯已经更换,11个节能灯仍然存在。

样例输入复制

5 4
3 10 5 2 7
10
5 1 4 8 7 2 3 6 4 7

样例输出复制

4 0
1 1
3 6
5 1
5 1
2 0
3 2
4 4
3 6
5 1

 解题思路:从左到右每次查找小于等于剩余灯泡数目的房间,然后把该房间的灯泡数目改成无穷大,即表示成不可更换灯泡了

 

实现的话,当然是用线段树了,感觉好像就差不多就一个操作,就是查询操作,不过每次查询到结果就把该房间的灯泡数更新成无穷大,这样可以节省点时间复杂度,就OK啦。

 

需要注意的是,在同一天,可能会更换多个房间的灯泡,这时候就需要用个while语句来处理了。还有一点就是当全部房间都被更换完毕后,就不会每天有灯泡了,也就是说答案就不变了,这点也是需要注意的。

 

开始模板都敲错了,竟然找错误找了老半天,太菜了。。。

附上代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define maxn 100005
#define inf 0x3f3f3f3f
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define pushup() tree[root]=min(tree[root<<1],tree[root<<1|1])
int tree[maxn<<2];
int n,m,q,day[maxn],cnt;
struct node{
    int room;  //房间数
    int num;   //剩余的灯泡数
}ans[maxn];

void build(int l,int r,int root)
{
    if(l==r)
    {
        scanf("%d",&tree[root]);
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    pushup();
}
/*
void update(int pos,int val,int l,int r,int root)
{
    if(l==r)
    {
        tree[root]=val;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid)
        update(pos,val,lson);
    else
        update(pos,val,rson);
    pushup();
}
*/
int query(int val,int l,int r,int root)
{
    if(l==r)
    {
        int z=tree[root];
        tree[root]=inf;
        return z;
    }
    int mid=l+r>>1;
    int x=0;
    if(val>=tree[root])  //判断是否有小于等于灯泡数的房间
    {
        if(tree[root<<1]<=val)  //是否可以去靠左边的房间
            x=query(val,lson);
        else  //左边去不了就去右边的
            x=query(val,rson);
    }
    pushup();
    return x;
}

int main()
{
    scanf("%d%d",&n,&m);
    build(1,n,1);
    scanf("%d",&q);
    cnt=0;
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&day[i]);
        if(ans[i-1].room!=n)   //当所有的房间的灯泡都被换了后,就不用加了
            cnt+=m;
        ans[i].room=ans[i-1].room;
        int k=query(cnt,1,n,1);
        while(k!=0)
        {
            cnt-=k;
            ans[i].room++;
            k=query(cnt,1,n,1);
        }
        ans[i].num=cnt;
    }
    for(int i=1;i<=q;i++)
        printf("%d %d\n",ans[day[i]].room,ans[day[i]].num);
    return 0;
}

 

posted @ 2018-09-20 23:41  两点够吗  阅读(242)  评论(0编辑  收藏  举报