他们摆出了一座高高的香槟塔,牛牛负责听妞妞指挥,往香槟塔里倒香槟。
香槟塔有个很优雅的视觉效果就是如果这一层的香槟满了,就会从边缘处往下一层流去。
妞妞会发出两种指令,指令一是往第x层塔内倒体积为v的香槟,指令二是询问第k层塔香槟的体积为多少。
告诉你香槟塔每层香槟塔的初始容量,你能帮牛牛快速回答妞妞的询问吗?
第一行为两个整数n,m。表示香槟塔的总层数和指令条数。
第二行为n个整数ai,表示每层香槟塔的初始容量。第三行到第2+m行有两种输入,一种输入是“2 x v”表示往第x层倒入体积为v的香槟;另一种输入是“1 k”表示询问第k层当前有多少香槟。1 <= n, m <= 1000。
1 <= n ,m <= 200000,1 <= ai ,v <= 1000000000。
对于每个询问,输出一个整数,表示第k层香槟的容量。
1 2 8 2 1 9 1 1
8
5 4 1 2 2 10 1 1 3 2 2 5 2 4 3 1 4
0 4
/*思路:线段树维护区间剩余容量和,查询操作直接输出, 从x层倒入操作则二分查找倒入的液体能到达的层数r,此时x到r-1层剩余容量为0,故区间更新为0, 单点更新r层剩余容量 = x到r层总容量tmp - 导入液体总体积val (时间长没写线段树,忘了懒惰标记怎么用了,参考下楼里某位dalao的标记。很好用哈哈 */ #include <bits/stdc++.h> #define lc rt << 1 #define rc rt << 1 | 1 #define LL long long using namespace std; const int AX = 2e5 + 666 ; LL s[AX<<2] ; // 维护各层剩余容量和 int lazy[AX<<2]; LL v[AX] ; int n , m ; LL left_v , tmp ; void pushUp( int rt ){ s[rt] = s[lc] + s[rc]; return ; } void pushDown( int rt ){ if( lazy[rt] != -1 ){ s[lc] = s[rc] = 0 ; lazy[lc] = lazy[rc] = 1 ; lazy[rt] = -1 ; } return ; } void build( int rt , int l , int r ){ if( l == r ){ scanf("%lld",&s[rt]); v[l] = s[rt] ; return ; } int mid = ( l + r ) >> 1 ; build( lc , l , mid ); build( rc , mid + 1 , r ); pushUp(rt); } void update( int rt , int l , int r , int L , int R , int op ){ if( L > r || R < l ) return ; if( L <= l && R >= r ){ if( op ){ s[rt] = 0 ; lazy[rt] = 1 ; }else s[rt] = left_v ; return ; } int mid = ( l + r ) >> 1 ; pushDown( rt ) ; if( l <= mid ) update( lc , l , mid , L , R , op ); if( R > mid ) update( rc , mid + 1 , r , L , R , op ); pushUp(rt) ; } LL query( int rt , int l , int r , int L , int R ){ if( L <= l && R >= r ) return s[rt] ; int mid = ( l + r ) >> 1 ; LL ans = 0 ; pushDown( rt ); if( L <= mid ) ans += query( lc , l , mid , L , R ) ; if( R > mid ) ans += query( rc , mid + 1 , r , L , R ); return ans ; } int getR( int l , int r , int x , int val ){ // 查找从x层倒,能满(四声)到哪一层为止 while( l <= r ){ int mid = ( l + r ) >> 1 ; if( query( 1 , 1 , n , x , mid ) >= val ) r = mid - 1; else l = mid + 1 ; } tmp = query( 1 , 1 , n , x , l ); //查询被倒入液体触及的所有层总容量 return l ; } int main(){ memset( lazy , -1 , sizeof(lazy) ); cin >> n >> m ; build( 1 , 1 , n ) ; int op , x ; LL val ; while( m-- ){ scanf("%d",&op); if( op == 1 ){ scanf("%d",&x); printf("%lld\n",v[x] - query( 1 , 1 , n , x , x ) ); }else{ scanf("%d%lld",&x,&val); int r = getR( x , n , x , val ) ; left_v = tmp - val ; if( left_v <= 0 ){ //正好倒满或倒满地上了 update( 1 , 1 , n , x , r , 1 ); }else{ if( r == 1 ) update( 1 , 1 , n , 1 , 1 , 0 ); //第一层都倒不满 else{ //x到r-1层被倒满,剩余体积设为0,r层剩余left_v体积 = tmp(x到r层总容量)-val(总共倒入体积) update( 1 , 1 , n , x , r - 1 , 1 ) ; update( 1 , 1 , n , r , r , 0 ); } } } } return 0 ; }
Python Solution
假设第 层初始状态值为 ,则装满的情况为该层状态值达到 。
假如第1层容积为2,则初始状态值为-2,倒入体积3的酒,则状态值归0,剩余体积1的酒向下流动。
n, m = [int(i) for i in input().split()] a = [int(i) for i in input().split()] st = [-i for i in a] all_ml = [[int(i) for i in input().split()] for i in range(m)] def pour(st, ml): '''香槟塔的第x层到体积v的酒''' x = ml[1]-1 v = ml[2] while True: v = v + st[x] if v < 0: st[x] = v break else: st[x] = 0 x += 1 if x == len(st): break return st def ask(a, st, ml): '''k层装酒量=k层容积+k层状态值''' k = ml[1] print(a[k-1]+st[k-1]) for ml in all_ml: if ml[0] == 2: st = pour(st, ml) else: ask(a, st, ml)
/* 判断,循环。哭了,同样的程序python死活超时 */ #include <bits/stdc++.h> using namespace std; #define N 200001 int a[N], b[N]; int main(void) { //freopen("input.txt", "r", stdin); int n, m, op, x, v, k; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } while(m--) { scanf("%d", &op); if(op == 1) { scanf("%d", &k); printf("%d\n", b[k]); } else { scanf("%d%d", &x, &v); while(x <= n && v > 0) { if(a[x] - b[x] < v) { v -= a[x] - b[x]; b[x] = a[x]; x++; } else { b[x] += v; v = 0; } } } } return 0; }
n, m = map(int, input().strip().split()) a = list(map(int, input().strip().split())) # 初始情况下每一层被占用的容积为0 occupy = [0]*n for _ in range(m): temp = list(map(int, input().strip().split())) if len(temp) == 3: op, x, v = temp else: op, x = temp if op == 2: # 倒香槟操作 idx = x - 1 # 初始层号 while v and idx < n: if v + occupy[idx] > a[idx]: # 如果要倒的香槟和这一层已经被倒的体积超过了这一层的容积,就要向下流 v -= a[idx] - occupy[idx] # 向下流的体积 occupy[idx] = a[idx] # 更新本层被占用的容积 idx += 1 # 向下更新层号 if idx == n: break else: # 更新本层被占用的容积 occupy[idx] = v + occupy[idx] # 否则没有向下层流的体积 v = 0 else: # 询问操作 print(occupy[x - 1])
#include <stdio.h> #include <vector> #include <algorithm> #include <string.h> #include <limits.h> #include <string> #include <iostream> #include <queue> #include <math.h> #include <map> #include <stack> #include <set> #include <list> #include <forward_list> #define left (now<<1) #define right ((now<<1)+1) #define mid ((l + r) >> 1) #define midmid ((r + mid) >> 1) #define LONG_LONG_MIN -9223372036854775808ll #define LONG_LONG_MAX 9223372036854775807ll using namespace std; typedef long long int ll; const int MAXN = 2e5 + 10; const int MOD = 1e9 + 7; int n,m,nxt[MAXN],pre[MAXN]; ll now[MAXN],a[MAXN]; void init(){ for(int i = 1; i <= n + 1; ++i){ now[i] = 0; nxt[i] = i + 1; pre[i] = i - 1; } } int main(){ scanf("%d%d",&n,&m); init(); for(int i = 1; i <= n; ++i){ scanf("%lld",&a[i]); } a[n + 1] = LONG_LONG_MAX / 2ll; for(int i = 1; i <= m; ++i){ int command; scanf("%d",&command); if(command == 2){ int x; ll v; scanf("%d%lld",&x,&v); while(v > 0){ ll p = a[x] - now[x]; if(p >= v){ now[x] += v; v = 0; }else{ now[x] = a[x]; v -= p; nxt[pre[x]] = nxt[x]; pre[nxt[x]] = pre[x]; x = nxt[x]; } } }else{ int x; scanf("%d",&x); printf("%lld\n",now[x]); } } return 0; }
#include <bits/stdc++.h> using namespace std; int main(){ int n,m,c,x,y; cin>>n>>m; int a[n+1],b[n+1]; memset(b,0,sizeof(b)); for(int i=1;i<=n;i++) cin>>a[i]; for(int i=0;i<m;i++){ cin>>c; if(c==1){ cin>>x; cout<<b[x]<<endl; }else{ cin>>x>>y; int t = a[x]-b[x]; while(y>t && x<=n){ b[x] += t; if(x<=n){ y -= t; x++; t = a[x] - b[x]; }else break; } if(x<=n) b[x] += y; } } return 0; }
#include <bits/stdc++.h> using namespace std; int main() { int n,m,q,x,v,k; cin>>n>>m; int a[n],b[n]; for(int i=0;i<n;i++) { cin>>a[i]; b[i]=0; } while(m--) { cin>>q; if(q==1) { cin>>k; cout<<b[k-1]<<endl; } if(q==2) { cin>>x>>v; x--; while(x<n&&v>0) { if ((a[x]-b[x])<v) { v -= a[x] - b[x]; b[x] = a[x]; x++; } else { b[x] += v; v = 0; } } } } return 0; }
#include <bits/stdc++.h> #define ls o*2 #define rs o*2+1 using namespace std; const int N = 2e5+7; int x,y,v,n; long long O[N<<2],vol[N]; bool laz[N<<2]; void build(int o,int l,int r){ if(l==r){ scanf("%lld",&vol[l]); O[o] = vol[l]; }else{ int mid = l+(r-l)/2; build(ls,l,mid); build(rs,mid+1,r); O[o] = O[ls]+O[rs]; } } void pushdown(int o){ if(laz[o]){ O[ls] = O[rs] = 0; laz[ls] = laz[rs] = 1; laz[o] = 0; } } void update(int o,int l,int r,int op){ if(x>r||y<l)return; if(x<=l&&y>=r){ if(op==1){ laz[o] = 1; O[o] = 0; } else O[o] = v; }else{ int mid = l+(r-l)/2; pushdown(o); if(x<=mid)update(ls,l,mid,op); if(y>mid)update(rs,mid+1,r,op); O[o] = O[ls]+O[rs]; } } long long query(int o,int l,int r,int L,int R){ if(L<=l&&R>=r)return O[o]; else{ int mid = l+(r-l)/2; long long ans = 0; pushdown(o); if(L<=mid)ans += query(ls,l,mid,L,R); if(R>mid)ans += query(rs,mid+1,r,L,R); return ans; } } int find_pos(int l,int r,long long &res){ int mid; while(l<r){ mid = l+(r-l)/2; if(query(1,1,n,x,mid)<v)l = mid+1; else r = mid; } res = query(1,1,n,x,l); return l; } int main(){ int m; scanf("%d %d",&n,&m); build(1,1,n); while(m--){ int op; scanf("%d",&op); if(op==1){ scanf("%d",&x); printf("%lld\n",vol[x]-query(1,1,n,x,x)); }else{ long long res = 0; scanf("%d %d",&x,&v); y = find_pos(x,n,res); v = res - v; if(res!=0){ if(y==n)update(1,1,n,1); else{ if(y==1){ x = y; update(1,1,n,0); } else{ y--;update(1,1,n,1); y++;x = y; update(1,1,n,0); } } } else update(1,1,n,1); } } return 0; }
注意:不能用for循环,for循环的时间复杂度太大,要用while
import java.util.*; public class Main{ public static void main(String args[]){ Scanner sc=new Scanner(System.in); int ceng=sc.nextInt(); int zhiling=sc.nextInt(); int[] churong=new int[ceng]; int[] xiangrong=new int[ceng]; int j=0; while(j<ceng){ int A1=sc.nextInt(); churong[j]=A1; xiangrong[j]=0; j++; } int z=0; while(z<zhiling){ int gu=sc.nextInt(); if(gu==1){ int k=sc.nextInt(); int l=xiangrong[k-1]; System.out.println(l); }else{ int b=sc.nextInt(); int x=b-1; int v=sc.nextInt(); while(v>0&&x<ceng){ //如果 杯子已有的水<杯子 并且v<杯子-水 if(xiangrong[x]<churong[x]&&v<churong[x]-xiangrong[x]){ xiangrong[x]=xiangrong[x]+v; v=0; } else { //v=v-(杯子-水) v=v-(churong[x]-xiangrong[x]); xiangrong[x]=churong[x]; x++; } } } z++; } } }
#include <iostream> #include <vector> #include <unordered_map> using namespace std; unordered_map<int,int> next_layer; int dfs(int layer,int v,vector<int>& cur,vector<int>& volume){ if(layer==volume.size()) return layer; int tmp=volume[layer]-cur[layer]; if(tmp>=v){ cur[layer]+=v; return layer; } cur[layer]=volume[layer]; next_layer[layer]=dfs(next_layer[layer],v-tmp,cur,volume); return next_layer[layer]; } int main(){ int n,m; cin>>n>>m; vector<int> volume(n+1); vector<int> cur(n+1,0); for(int i=1;i<=n;++i) cin>>volume[i]; for(int i=1;i<=n;++i) next_layer[i]=i+1; while(m--){ int op; cin>>op; if(op==1){ int layer; cin>>layer; cout<<cur[layer]<<endl; } else{ int layer,v; cin>>layer>>v; if(volume[layer]-cur[layer]>=v) cur[layer]+=v; else{ next_layer[layer]=dfs(layer,v,cur,volume); } } } return 0; }
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); while(sc.hasNext()){ int n = sc.nextInt(); int m = sc.nextInt(); int[][] arr = new int[n][2]; for(int i=0;i<n;i++){ arr[i][0] = sc.nextInt(); } for(int i=0;i<m;i++){ int o = sc.nextInt(); if(o==1){ int x = sc.nextInt()-1; System.out.println(arr[x][1]); }else{ int x = sc.nextInt()-1; int v = sc.nextInt(); while(v>0 && x<n){ if(v <= arr[x][0]){ arr[x][1] += v; arr[x][0] -= v; v = 0; //x++; }else{ v -= arr[x][0]; arr[x][1] += arr[x][0]; arr[x][0] = 0; x++; } } } } } } }
// 38行代码结束战斗,C++ #include <iostream> #include <vector> using namespace std; int main(){ //输入数据 int numLayer, numCmd; cin >> numLayer >> numCmd; vector<int> volume(numLayer, 0), used(numLayer, 0); for (int i=0;i<numLayer;++i) cin >> volume[i]; while (numCmd--){ int cmd; cin >> cmd; //如果是查询 if (cmd == 1){ int where; cin >> where; cout << used[where-1] << endl; } //如果是灌水 else if (cmd == 2){ int where, amount; cin >> where >> amount; while (amount > 0){ //1.边界判断:全都满了 if (where > numLayer) break; //2.如果不够装满当前层 if (amount <= volume[where-1] - used[where-1]){ used[where-1] += amount; amount = 0; } //3.如果当前层满了,但是还有剩余 else{ amount -= volume[where-1] - used[where-1]; used[where-1] = volume[where-1]; ++where; } } } } return 0; }比较简单,跟着题目意思走就行
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * @Author: coderjjp * @Date: 2020-05-08 17:47 * @Description: * @version: 1.0 */ public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line1[] = br.readLine().split(" "); int n = Integer.valueOf(line1[0]);//层数 int m = Integer.valueOf(line1[1]);//总指令数 int V[] = new int[n+1]; String[] line2 = br.readLine().split(" "); for (int i = 0; i < n; i++) V[i+1] = Integer.valueOf(line2[i]); int cur[] = new int[n+1];//初始体积 while (m-- > 0){ String linex[] = br.readLine().split(" "); int order[] = new int[linex.length]; for (int i = 0; i < linex.length; i++) order[i] = Integer.valueOf(linex[i]); if (order[0] == 1) System.out.println(cur[order[1]]); else{ int rem = order[2]; for (int i = order[1]; i <= n && rem > 0; i++){ if (cur[i] == V[i]) continue; if (rem >= V[i]-cur[i]){ rem = rem - (V[i] - cur[i]); cur[i] = V[i]; }else { cur[i] += rem; rem = 0; } } } } } }
import copy n,m = map(int,input().split()) nums = list(map(int,input().split())) nums = [0]+nums flag = copy.deepcopy(nums) for _ in range(m): op = list(map(int,input().split())) if len(op)==3: k,v= op[1],op[2] index = k while v>0 and index<n: if v>flag[index]: v = v- flag[index] flag[index] = 0 index+=1 else: flag[index] = flag[index]-v v = 0 else: k = op[1] print(nums[k] - flag[k])
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt();//香槟塔总层数 int m = sc.nextInt();//指令条数 long[] a = new long[n];// 初始容量 for (int i = 0; i < n; i++) { a[i] = sc.nextLong(); } long[] champagnes = new long[n];//塔的 Champagne 量 for (int i = 0; i < m; i++) { int flag = sc.nextInt(); if (flag == 1) { int k = sc.nextInt() - 1;//询问第 k 层 System.out.println(champagnes[k]); } else { int x = sc.nextInt() - 1;//往第 x 层倒 Champagne long v = sc.nextLong();//倒入的 Champagne 体积 pourChampagne(x, v, a, champagnes); } } } private static void pourChampagne(int towerIndex, long volume, long[] a, long[] champagnes) { if (towerIndex >= a.length) { return; } long capacity = a[towerIndex];//当前层的容量 long champagne = champagnes[towerIndex];//当前层的 Champagne 量 if (champagne == capacity) { pourChampagne(towerIndex + 1, volume, a, champagnes); return; } if (champagne + volume <= capacity) { champagnes[towerIndex] += volume; } else { long residual = volume - (capacity - champagne);//当前层填满后流入下一层的余量 champagnes[towerIndex] = capacity; pourChampagne(towerIndex + 1, residual, a, champagnes); } } }
c,z=list(map(int,input().split(" "))) r1=list(map(int,input().split(" "))) r2=[0 for i in range(c)] re=[] while z>0: in1=list(map(int,input().split(" "))) if in1[0]==1: re+=[r2[in1[1]-1]] elif in1[0]==2: while in1[1]<=c : k=in1[1]-1 if r1[k]==r2[k]: in1[1]+=1 continue if r1[k]>r2[k]: r2[k]=r2[k]+in1[2] if r2[k]>=r1[k]: in1[2]=r2[k]-r1[k] r2[k]=r1[k] in1[1]+=1 else:break z-=1 for i in re: print(i)
n, m = map(int, input().split()) a = [int(i) for i in input().split()] b = [0 for i in range(n)] for i in range(m): order = [int(j) for j in input().split()] if order[0] == 1: print(b[order[1]-1]) else: k = 0 while b[order[1]+k-1]+order[2] > a[order[1]+k-1] and order[1]+k < n: order[2] = order[2] - (a[order[1]+k-1]-b[order[1]+k-1]) b[order[1]+k-1] = a[order[1]+k-1] k += 1 b[order[1] + k-1] += min(order[2], (a[order[1]+k-1]-b[order[1] + k-1]))
#include <iostream> #include <vector> using namespace std; int main(void){ int n, m, oper, i, v, tmp_vol; cin>>n>>m; vector<int> volume(n, 0), contain(n, 0); for(int i = 0; i < n; ++i) cin>>volume[i]; while(m--){ cin>>oper>>i; --i; if(oper == 1) cout<<contain[i]<<endl; else{ cin>>v; while(v + contain[i] >= volume[i] && i < n){ v = v + contain[i] - volume[i]; contain[i] = volume[i]; //写在上一句语句前面 //v = v + contain[i] - volume[i]; ++i; } //用+=而不是= if(i < n) contain[i] += v; } } return 0; }