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";  //输出
        }
    }
}

求通过……