CF371D 的题解
原题跃迁窗口
本蒟蒻代码较复杂,勿抄。
解析
本体的正确做法其实就是链表,但由于用链表具有很大的不确定性(尤其在上机考试中),所以不能直接用。
但并非一定就要用并查集,我们可以不用指针,纯模拟,模出链表,模出 AC。
思路
就像链表一样,数组中有三样东西:数值,前面的“大哥”,后面的“小弟”。
一个沙漏如果满了,就把多余的放到“小弟”那儿。因为这个沙漏已经满了,所以它也就“失去了价值”,“大哥”就把它的“小弟”当成自己的“小弟”,“小弟”就把它的“大哥”当成了自己的大哥。
这纯属黑帮内斗。
此外,还需要一点点小小的优化。
如果将上述内容全部放在 while 中,就会超时。而如果将头指针(“大哥”)和尾指针(“小弟”)放在 while 外面,就可以减少一些时间。
程序
#include <bits/stdc++.h> //万能头
using namespace std;
int n,m,i,x,y,z,a[200001],yy,s; //定义
struct no{ //定义一个结构体 b
int a, t, w;
// 数值(水量) “大哥” “小弟”
}b[200002];
int main(){
ios::sync_with_stdio(0); //有趣的加速代码
cin.tie(0);cout.tie(0);
cin>>n;
for(i=1;i<=n;i++) cin>>a[i],b[i].t=i-1,b[i].w=i+1; //确定“大哥”和“小弟”
cin>>m;
for(i=1;i<=m;i++){
cin>>x;
if(x==1){
cin>>y>>z;
s=0; //默认没有溢出(不会有水流到下一层)
yy=y; //保存初始位置
b[y].a+=z; //倒水
while(b[y].a>=a[y]&&y!=n+1){ //溢出了,并且没有越界
b[b[y].w].a+=b[y].a-a[y]; //把多余的水加到“小弟”那里去
b[y].a=a[y]; //水量变成正常值
y=b[y].w; //找到“小弟”
s=1; //我来过(至少溢出过一次)
}
if(s){ //如果溢出过,也就是说明有人要在“内斗”中“死去”
b[y].t=b[yy].t; //“小弟”认“大哥”
b[yy].w=y; //“大哥”认“小弟”
}
}
if(x==2){
cin>>y;
cout<<b[y].a<<"\n"; //输出
}
}
}
求通过……