【CodeForces - 371D】Vessels(思维,元素合并,并查集)

题干:

There is a system of n vessels arranged one above the other as shown in the figure below. Assume that the vessels are numbered from 1 to n, in the order from the highest to the lowest, the volume of the i-th vessel is ai liters.

Initially, all the vessels are empty. In some vessels water is poured. All the water that overflows from the i-th vessel goes to the (i + 1)-th one. The liquid that overflows from the n-th vessel spills on the floor.

Your task is to simulate pouring water into the vessels. To do this, you will need to handle two types of queries:

  1. Add xi liters of water to the pi-th vessel;
  2. Print the number of liters of water in the ki-th vessel.

When you reply to the second request you can assume that all the water poured up to this point, has already overflown between the vessels.

Input

The first line contains integer n — the number of vessels (1 ≤ n ≤ 2·105). The second line contains n integers a1, a2, ..., an — the vessels' capacities (1 ≤ ai ≤ 109). The vessels' capacities do not necessarily increase from the top vessels to the bottom ones (see the second sample). The third line contains integer m — the number of queries (1 ≤ m ≤ 2·105). Each of the next m lines contains the description of one query. The query of the first type is represented as "1 pi xi", the query of the second type is represented as "2 ki" (1 ≤ pi ≤ n, 1 ≤ xi ≤ 109, 1 ≤ ki ≤ n).

Output

For each query, print on a single line the number of liters of water in the corresponding vessel.

Examples

Input

2
5 10
6
1 1 4
2 1
1 2 5
1 1 4
2 1
2 2

Output

4
5
8

Input

3
5 10 8
6
1 1 12
2 2
1 1 6
1 3 2
2 2
2 3

Output

7
10
5

解题报告:

    先来一发暴力TLE,然后发现可以用并查集的区间合并。

TLE代码:

#include<bits/stdc++.h>using namespace std;
const int MAX = 2e5 + 5;
int a[MAX],rest[MAX],ne[MAX];int main()
{int n,m,x,y,op;cin>>n;for(int i = 1; i<=n; i++) scanf("%d",a+i),rest[i]=a[i],ne[i]=i;cin>>m;while(m--) {scanf("%d",&op);if(op == 2) {scanf("%d",&x);printf("%d\n",a[x] - rest[x]);}else {scanf("%d%d",&x,&y);while(rest[ne[x]] == 0 && ne[x] <= n) ne[x]++;//ne[x]=ne[x+1];while(y>0 && ne[x]<=n) {if(y>=rest[ne[x]]) {y-=rest[ne[x]];rest[ne[x]]=0;ne[x]++;	}else rest[ne[x]]-=y,y=0;}}}return 0 ;} 
/*
in:
10
71 59 88 55 18 98 38 73 53 58
20
1 5 93
1 7 69
2 3
1 1 20
2 1
2 10
1 6 74
1 7 100
1 9 14
2 3
2 4
2 7
1 3 31
2 4
1 6 64
2 2
2 2
1 3 54
2 9
2 1
1 6 86
out:
0
0
0
0
38
0
0
0
53
20*/
#include<bits/stdc++.h>using namespace std;
const int MAX = 2e5 + 5;
int a[MAX],rest[MAX],ne[MAX];int main()
{int n,m,x,y,op;cin>>n;for(int i = 1; i<=n; i++) scanf("%d",a+i),rest[i]=a[i],ne[i]=i;ne[n+1] = n+1;cin>>m;while(m--) {scanf("%d",&op);if(op == 2) {scanf("%d",&x);printf("%d\n",a[x] - rest[x]);}else {scanf("%d%d",&x,&y);while(rest[ne[x]] == 0 && ne[x] <= n) {if(ne[x]!=ne[x+1])ne[x]=ne[x+1];else ne[x]++,ne[x+1]++;}while(y>0 && ne[x]<=n) {if(y>=rest[ne[x]]) {y-=rest[ne[x]];rest[ne[x]]=0;//ne[x]++;//ne[x]=ne[ne[x+1]];if(ne[x]!=ne[x+1])ne[x]=ne[x+1];else ne[x]++,ne[x+1]++;					}else rest[ne[x]]-=y,y=0;}}}return 0 ;} 

后来发现可以ne[x]=ne[ne[x+1]],然后就可以ne[x]=ne[ne[ne[x+1]]]以此类推,再仔细一看,这不就是并查集的getf函数的过程吗。

开搞:

AC代码:

#include<bits/stdc++.h>using namespace std;
const int MAX = 2e5 + 5;
int a[MAX],rest[MAX],f[MAX];
int getf(int v) {return f[v] == v ? v : f[v] = getf(f[v]);
} 
void merge(int u,int v) {//默认u < vint t1 = getf(u);int t2 = getf(v);if(t1 != t2) f[t1] = t2;
}
int main()
{int n,m,x,y,op;cin>>n;for(int i = 1; i<=n; i++) scanf("%d",a+i),rest[i]=a[i],f[i]=i;f[n+1] = n+1;cin>>m;while(m--) {scanf("%d",&op);if(op == 2) {scanf("%d",&x);printf("%d\n",a[x] - rest[x]);}else {scanf("%d%d",&x,&y);int t1=getf(x);while(y>0 && t1 <= n) {t1 = getf(t1);if(y>=rest[t1] && t1 <= n) {//只能装rest[t1]的水了 y-=rest[t1];rest[t1]=0;merge(t1,t1+1);				}else rest[t1]-=y,y=0;}}}return 0 ;} 

别忘处理边界啊,就是已经到最下面那个瓶子哪里了,所以两个地方都需要t1<=n,给个样例:

10
71 59 88 55 18 98 38 73 53 58
8
1 5 93
1 7 69
1 1 20
1 6 74
1 7 100
1 9 14
1 6 64
2 2

本该是1,却输出13吗,这其实是一个越界的值,这里的越界不是因为无限递归到2e5+5,而是在merge(10,11)的时候,因为f[11]没有初始化,所以f[11]=0,所以不会报错!程序也不会进入死循环但是相当于f[..6,7,8,9,10]这些本该=10的,都变为了=0;所以覆盖了之前的结果!

解决方法也有很多,

1.比如在if中也加上t1<=n。

2.或者初始化的时候for(int i = 1; i<MAX; i++) f[i]=i;而不是只初始化到n,这样就会在while中给break掉。所以思考问题时要注意整个程序可能用到的下标!而不是正解要用到的下标,或者说对于输入数据的合法的下标! 

3.还是针对初始化,加上rest[n+1] = INT_MAX;

     即:一般数组模拟问题都需要初始化一下边界值,比如从i=1开始读入数组,那就需要更新一下a[0],a[n+1],防止越界!这种题目太多太多,在此不再赘述。总之数组模拟真实情况的场景,最好都处理一下边界。不然就可能发生各种无法解释的脑残事件。

 

但是针对2和3这两种方法,会TLE8,不知道为什么、、、

初始化的时候把rest改成全都INT_MAX,也可以AC,,奇怪了

AC代码:

#include<bits/stdc++.h>using namespace std;
const int MAX = 2e5 + 5;
int a[MAX],rest[MAX],f[MAX];
int getf(int v) {return f[v] == v ? v : f[v] = getf(f[v]);
} 
void merge(int u,int v) {//默认u < vint t1 = getf(u);int t2 = getf(v);if(t1 != t2) f[t1] = t2;
}
int main()
{int n,m,x,y,op;cin>>n;for(int i = 1; i<MAX; i++) f[i]=i,rest[i]=INT_MAX; for(int i = 1; i<=n; i++) scanf("%d",a+i),rest[i]=a[i],f[i]=i;rest[n+1] = INT_MAX;f[n+1] = n+1;cin>>m;while(m--) {scanf("%d",&op);if(op == 2) {scanf("%d",&x);printf("%d\n",a[x] - rest[x]);}else {scanf("%d%d",&x,&y);int t1=getf(x);while(y>0 && t1 <= n) {t1 = getf(t1);if(y>=rest[t1]) {//只能装rest[t1]的水了 y-=rest[t1];rest[t1]=0;merge(t1,t1+1);				}else rest[t1]-=y,y=0;}}}return 0 ;} 

总结:

   1WA了啊,因为没加ne[x]<=n这个条件,仔细想想,为什么要加这个条件。


再附一个网络版的AC代码:(是有点记忆化的思想在里面的)

//wlb 记忆化的 也算是并查集吧
#include<bits/stdc++.h>
using namespace std;
int num[210000],pre[210000],now[210000];
int pour(int x,int y) {if(x==-1) return x;if(now[x]==num[x]) return pre[x]=pour(pre[x],y);else if(now[x]<num[x]) {now[x]+=y;if(now[x]>num[x]) {int t=now[x]-num[x];now[x]=num[x];return pre[x]=pour(pre[x],t);} else return x;}
}
int main() {int n,a,b,m;cin>>n;for(int i=1; i<=n; i++) {scanf("%d",&num[i]);pre[i]=i+1;now[i]=0;}pre[n]=-1;scanf("%d",&m);while(m--) {int op;scanf("%d",&op);if(op==1) {scanf("%d%d",&a,&b);pour(a,b);} else {scanf("%d",&a);printf("%d\n",now[a]);}}return 0 ;
}

终于找到了上面那些方法TLE的真正原因!

其实,改成这样就好了。

#include<bits/stdc++.h>using namespace std;
const int MAX = 2e5 + 5;
int a[MAX],rest[MAX],f[MAX];
int getf(int v) {return f[v] == v ? v : f[v] = getf(f[v]);
} 
void merge(int u,int v) {//默认u < vint t1 = getf(u);int t2 = getf(v);if(t1 != t2) f[t1] = t2;
}
int main()
{int n,m,x,y,op;cin>>n;for(int i = 1; i<=n; i++) scanf("%d",a+i),rest[i]=a[i],f[i]=i;
//	rest[n+1] = INT_MAX;f[n+1] = n+1;cin>>m;while(m--) {scanf("%d",&op);if(op == 2) {scanf("%d",&x);printf("%d\n",a[x] - rest[x]);}else {scanf("%d%d",&x,&y);int t1=getf(x);while(t1 <= n && y>0) {if(y>=rest[t1]) {//只能装rest[t1]的水了 y-=rest[t1];rest[t1]=0;merge(t1,t1+1);	t1 = getf(t1);			}else rest[t1]-=y,y=0;}}}return 0 ;} 

聪明的你一定看得出来,其实就是把t1 = getf(t1); 移到if里面了,想一下,确实是啊!我操作完了之后需要准备出下一个状态并交由while去判断,而不是while完了之后再找下一个状态!你如果while完了再转移到下一个状态,那肯定要加if(...&& t1<=n)啊!因为这里就需要再判断一遍while里面的东西!!而因为一个t1=getf(t1),其中y没有参与,所以if里面不需要加上while里面的(y>0),所以就有了第一个AC代码的样子、、、但是其实你要知道这是不对的!

至于为什么不在if中加(t1<=n)而是在rest[n+1]=INT_MAX这样是TLE的,我是这样认为,还没有验证正确性:

     因为你的想法是弄一个无穷大来表示可以盛放无穷多的水,但是INT_MAX在这里不是无穷大了!这不是图论啊!每一次倒水的范围是1e9!所以倒两次1e9,你这个rest[n+1]无穷大就减没了,甚至rest[n+1]变成负数了,,就进入无限递归了   ,因为if(y>=rest[n+1])这个永远成立,进入if后,y变大了?!然后rest[t1]=0,然后下一层还是可以进。。。(不不不,可能就退出while了)

   emmm并且如果你没有for(i=0 -> MAX) f[i]=i的话,那到t1=n的时候,merge(n,n+1)了之后因为f[n+1]=n+1了所以没事,然后到while这里,注意这时候t1还是n!所以还是可以进入while,然后merge(n+1,n+2),,这时候凉凉了,所有以n为根节点的节点全都变为n+2的祖先节点,而f[n+2]=0,(因为没有初始化!)所以凉凉,在这之后的操作,我要找倒水的位置了,结果跑回0节点这个非法节点了,然后因为rest[0]=0,所以肯定还会进这个if,然后merge(0,1),,这就真凉了,绕圈了。

    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/441503.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【UVA - 10891 Game of Sum 】【HRBUST - 1622】 Alice and Bob (区间dp,博弈问题)

题干&#xff1a; 有一个长度为N的整数序列&#xff0c;Alice和Bob轮流取数&#xff0c;Alice先取。每次玩家只能从左端或者右端 取一个或多个数&#xff0c;但不能两端都取。所有数都被取走后游戏结束&#xff0c;然后统计每个人取走的所有数之和&#xff0c; 作为各自的得分…

code iban 是有什么组成_EAN-128码和Code-128码的区别

什么是Code-128码&#xff1f;什么是EAN-128码&#xff1f;二者之间有什么区别&#xff1f;接下来小编就给大家解除心中的疑惑。Code-128码是一种高密度的条形码&#xff0c;可表示从 ASCII 0 到ASCII 127 共128个字符&#xff08;其中包含数字&#xff0c;字母&#xff0c;符号…

计算机中丢失setupxml.dll,Win7电脑安装VideoStudio Pro X6显示丢失SetupXML.dll文件怎么解决...

最近有win7系统用户在电脑安装VideoStudio Pro X6软件的时候&#xff0c;突然出现错误的提示&#xff0c;显示无法启动此程序&#xff0c;因为计算机中丢失SetupXML.dll。尝试重新安装该程序来解决此问题&#xff0c;要怎么办呢&#xff0c;下面给大家讲解一下Win7电脑安装软件…

怎么p出模糊的照片_36. 盲去卷积 - 更加实用的图像去模糊方法

本文同步发表在我的微信公众号和知乎专栏“计算摄影学”&#xff0c;欢迎扫码关注&#xff0c;上一篇文章35. 去卷积&#xff1a;怎么把模糊的图像变清晰&#xff1f;吸引了很多朋友的关注。在这篇文章里面&#xff0c;我给大家讲了一种叫做“非盲去卷积”的方法&#xff0c;当…

【CodeForces - 1038A 】Equality (思维水题,预处理字符串)

题干&#xff1a; You are given a string ss of length nn, which consists only of the first kk letters of the Latin alphabet. All letters in string ss are uppercase. A subsequence of string ss is a string that can be derived from ss by deleting some of its…

docker修改镜像的存储位置_云原生存储详解:容器存储与 K8s 存储卷(内含赠书福利)...

作者 | 阚俊宝 阿里巴巴技术专家参与文末留言互动&#xff0c;即有机会获得赠书福利&#xff01;导读&#xff1a;云原生存储详解系列文章将从云原生存储服务的概念、特点、需求、原理、使用及案例等方面&#xff0c;和大家一起探讨云原生存储技术新的机遇与挑战。本文为该系列…

vb简易计算机器程序,vb简易计算器源码

代码如下&#xff1a;/***Author:乌鸟heart*Version:1.0*/Dim IntX As Double 全局变量&#xff0c;用于存储计算的数值Dim IntOperation As Double 标记运算类型Dim isBegin As Boolean 标记是否已经给IntX赋值Public Sub Clear() 清空命令函数screen.Caption ""En…

【CodeForces - 1038B 】Non-Coprime Partition (构造,数组特征)

题干&#xff1a; Find out if it is possible to partition the first nn positive integers into two non-empty disjoint sets S1S1 and S2S2 such that: gcd(sum(S1),sum(S2))>1gcd(sum(S1),sum(S2))>1 Here sum(S)sum(S) denotes the sum of all elements presen…

计算机专业用锐龙笔记本,轻松应对工作挑战——ThinkPad T14 锐龙版,适合办公的笔记本电脑...

拥有一部适合办公的笔记本电脑&#xff0c;可以成为商务人士忙碌工作中强有力的支持。联想旗下的ThinkPad 系列笔记本电脑&#xff0c;一直秉持为高端商务人士服务的理念&#xff0c;以稳定、流畅、安全的使用体验得到广泛认可。其中的ThinkPad T14 锐龙版&#xff0c;更是有着…

python tabula 使用方法_Python中os.walk()的使用方法

os.walk()主要用来扫描某个指定目录下所包含的子目录和文件。这篇文章将通过几个简单的例子来说明python中os.walk()的使用方法。假设我们的test文件夹有如下的目录结构&#xff1a;我们首先用os.walk扫描test文件夹下所有的子目录和文件&#xff1a;# 使用os.walk扫描目录 imp…

【CodeForces - 1038C】Gambling (博弈问题,优先队列模拟,贪心)

题干&#xff1a; Two players A and B have a list of nn integers each. They both want to maximize the subtraction between their score and their opponents score. In one turn, a player can either add to his score any element from his list (assuming his list…

乐乐勇智能教育机器人有多少型号_【头条】协作机器人平台化趋势将会是柔性自动化的破局之道...

智能机器人商情微信公众号&#xff0c;关注中国智能机器人行业热点与发展趋势&#xff0c;打造快捷高效的行业资讯交互平台。更多精彩内容&#xff0c;您可以点击标题下方的蓝字关注我们。导语艾利特平台级CS系列协作机器人全新发布9月15日上海工博会第一天&#xff0c;艾利特机…

计算机毕设结束语致谢,毕业设计结束语和致谢

毕业设计结束语和致谢时间&#xff1a;2021-01-17 20:08:40 分类&#xff1a;小结范文 | 毕业论文致谢词范文 | Word文档下载毕业设计结束语和致谢导语&#xff1a;论文致谢应以简短的文字对课题研究与论文撰写过程中间直接给予帮助的人员(例如指导教师、答疑教师及其他人员)…

*【HDU - 2819】Swap(二分图匹配,输出路径)(待证明:是否是最少交换次数?)

题干&#xff1a; Given an N*N matrix with each entry equal to 0 or 1. You can swap any two rows or any two columns. Can you find a way to make all the diagonal entries equal to 1? Input There are several test cases in the input. The first line of each …

CSS中属性个属性值怎么区分,[CSS] 详细解释 @media 属性与 (max

前言现在 HTML5/CSS3 很流行罢&#xff0c;也是未来时代的趋势。在 HTML5 带来的许多实用功能之后&#xff0c;CSS3也同带来了一些牛逼哄哄的功能呢。动画 animation转化 transform过渡 translation尽快这已足够让我们兴奋&#xff0c;许多之前必须用 JS 或 JQ 写的效果用 CSS …

西门子精智和精简面板区别_西门子S7-1200的功能与特点,应用范围介绍

S7-1200是西门子公司新推出的一款面向离散自动化系统和独立自动化系统的低端PLC。S7-1200采用了模块化设计&#xff0c;具备强大的工艺功能&#xff0c;适用于多种场合&#xff0c;可以满足不同的自动化需求。S7-1200的定位处于原有的SIMATIC S7-200和SIMATIC S7-300之间&#…

【HDU - 1281 】棋盘游戏 (经典的二分图匹配,匈牙利算法,枚举删除顶点,必须边,关建边)

题干&#xff1a; 小希和Gardon在玩一个游戏&#xff1a;对一个N*M的棋盘&#xff0c;在格子里放尽量多的一些国际象棋里面的“车”&#xff0c;并且使得他们不能互相攻击&#xff0c;这当然很简单&#xff0c;但是Gardon限制了只有某些格子才可以放&#xff0c;小希还是很轻松…

eclipse提示方法已过时_提高效率,eclipse上你可能不知道的技巧

一张思维导图1、控制台(console )日志输出另保存经常会遇到这种情况&#xff0c;习惯性的清掉控制台上的输出日志&#xff0c;再然后发现刚才的日志居然还有用&#xff0c;不得不又重新调试一遍&#xff0c;为了解决这种“手贱”的问题&#xff0c;我在网上搜了一些资料&#x…

【CodeForces - 144B 】Meeting (暴力枚举,水题,计算几何)

题干&#xff1a; The Super Duper Secret Meeting of the Super Duper Secret Military Squad takes place in a Super Duper Secret Place. The place is an infinite plane with introduced Cartesian coordinate system. The meeting table is represented as a rectangle…

html中超链接使用_干货 | HTML中表格的使用方法

HTML中的表格是由表格的标签组成HTML中的表格是由标签用于定义表格的列&#xff0c;标签为又是标签来分割列&#xff0c;形成一个完整的表格。表格的标签组合关系为&#xff1a;我是单元格1我是单元格2表格中可以插入文本、图片、列表、段落、表单、水平线等任何html标签&#…