https://www.cnblogs.com/violet-acmer/p/9720603.html
变量解释:
need[ i ] : 第 i 个房间含有的旧灯泡个数。
remain[ i ] : 第 i 月后,换完满足条件的房间的旧灯泡后剩余节能灯泡的个数。
total[ i ] : 前 i 个月换灯泡的房间数。
题意:
有n个房间,每个房间都有need[ i ] 个旧灯泡等着男主角去换,男主角Lpl每个月都会购买m个节能灯泡,按照输入顺序给房间换灯泡,如果当前房间满足条件,则全部换完,不满足,跳到下一个房间,重复当前步骤。
如果当前房间并不能将新灯泡全部用完,则留着新灯泡给下个月使用。
有q个询问,每个询问给你一个值mon,代表当前月,输出[1,mon]月换灯泡的房间个数,以及还玩灯泡后新灯泡的剩余个数。
题解:
最简单的方法就是暴力,从第一个月开始枚举所有的房间,知道所有的房间都换完,或来到询问的最大月份,毋庸置疑,此操作的时间复杂度为O(max_mon*n),而本题的数据范围为1~1e5,显然会超时,1e5需要的实践复杂度至多为n*logn。
换个思路,考虑一下线段树。
线段树中当前结点的val值存储的是左右孩子中需要换灯泡的最小值,对于第 i 个月份,优先更新满足条件的左孩子区间,当左孩子不满足条件是,回溯到右孩子区间,直到不满足条件跳出递归。
对于满足条件的房间,在更换完灯泡后,将其val值设为最大值INF,并向上更新其父亲的val。
具体细节,看代码............
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define ls(x) ((x)<<1) 6 #define rs(x) ((x)<<1 | 1) 7 #define INF 0x3f3f3f3f 8 const int maxn=1e5+50; 9 10 int need[maxn]; 11 int remain[maxn]; 12 int total[maxn]; 13 int lamps;//当前月份的新灯泡数量 14 int sum;//前 i 个月可以换灯泡的房间数 15 struct Node1 16 { 17 int l,r; 18 int val; 19 int mid(){ 20 return l+((r-l)>>1); 21 } 22 }segTree[4*maxn]; 23 void pushUp(int pos) 24 { 25 segTree[pos].val=min(segTree[ls(pos)].val,segTree[rs(pos)].val); 26 } 27 void buildTree(int l,int r,int pos) 28 { 29 segTree[pos].l=l,segTree[pos].r=r; 30 if(l == r) 31 { 32 segTree[pos].val=need[l]; 33 return ; 34 } 35 int mid=l+((r-l)>>1); 36 buildTree(l,mid,ls(pos)); 37 buildTree(mid+1,r,rs(pos)); 38 pushUp(pos); 39 } 40 void update(int pos,int i) 41 { 42 if(segTree[pos].l == segTree[pos].r && segTree[pos].val <= lamps) 43 { 44 lamps -= segTree[pos].val; 45 segTree[pos].val=INF;//当前房间换完灯泡后,设置成最大值 46 pushUp(pos>>1);//向上更新 47 48 sum++;//可以更换的房间数 ++ 49 return ; 50 } 51 if(segTree[pos].val <= lamps) 52 { 53 if(segTree[ls(pos)].val <= lamps)//优先判断左孩子是否满足条件 54 update(ls(pos),i); 55 update(rs(pos),i); 56 } 57 pushUp(pos>>1);//向上更新 58 } 59 void init() 60 { 61 lamps=0; 62 sum=0; 63 memset(remain,0,sizeof(remain)); 64 memset(total,0,sizeof(total)); 65 } 66 int main() 67 { 68 int n,m; 69 while(~scanf("%d%d",&n,&m)) 70 { 71 init(); 72 for(int i=1;i <= n;++i) 73 scanf("%d",need+i); 74 buildTree(1,n,1); 75 76 for(int i=1;i <= 100000;++i)//月份最多是100000 77 { 78 lamps=remain[i-1]+m; 79 update(1,i); 80 remain[i]=(total[i-1] == n ? remain[i-1]:lamps);//更新当前月份的剩余新灯泡数量 81 total[i]=sum;//更新前 i 个月可以更换的房间数 82 } 83 int q; 84 scanf("%d",&q); 85 for(int i=1;i <= q;++i) 86 { 87 int mon; 88 scanf("%d",&mon); 89 printf("%d %d ",total[mon],remain[mon]); 90 } 91 } 92 }