HDU 5575 Discover Water Tank 并查集+左偏树

来源:互联网 发布:c语言点滴pdf百度云 编辑:程序博客网 时间:2024/05/16 00:52

不妨假定初始答案为所有的无水询问,因为这样一定没有冲突。

然后枚举有水询问、水位线到这里时,答案能否更优。

若水位线达到某一高度,则可能淹没旁边的水箱,那么实际就变成了一个大水箱,所以考虑用并查集来优化,为保证合并顺序正确,先对有水询问按水位高度排序。

下面思考更新答案,朴素的做法是枚举此水位线下的有水询问和无水询问的差,但实际上因为有水询问的水位高度已经排序,我们会做大量重复枚举,所以考虑排序后来做,但是因为有合并操作,所以考虑用左偏树来维护无水询问。

 时间复杂度O(α(n) + mlogm)

#include <bits/stdc++.h>using namespace std;#define N 100010#define INF INT_MAXint n,m,l_b[N],r_b[N],l_t[N],r_t[N],x[N],o[N];int tot,v[N*2],l[N*2],r[N*2],d[N*2],heap[N*2];struct node{    int x,y;    bool operator<(const node&b) const    {        return y == b.y ? x < b.x : y < b.y;    }}q[N*2];int cnt,ans;int fa[N];int merge(int x,int y){    if(!x)        return y;    if(!y)        return x;    if(v[x] > v[y])        swap(x,y);    r[x] = merge(r[x],y);    if(d[l[x]] < d[r[x]])        swap(l[x],r[x]);    d[x] = d[r[x]] + 1;    return x;}inline int init(int x){    tot++;    v[tot] = x;    l[tot] = r[tot] = d[tot] = 0;    return tot;}inline int insert(int x,int y){    return merge(x,init(y));}inline int top(int x){    return v[x];}inline int pop(int x){    return merge(l[x],r[x]);}int getfa(int x){    if(x == fa[x])        return x;    fa[x] = getfa(fa[x]);    return fa[x];}void mergeSet(int _x,int _y){    _x = getfa(_x);    _y = getfa(_y);    if(_x == _y)        return;    fa[_x] = _y;    if(_x < _y)    {        l_b[_y] = l_b[_x];        r_t[l_t[_x]] = _y;        l_t[_y] = l_t[_x];    }    else    {        r_b[_y] = r_b[_x];        l_t[r_t[_x]] = _y;        r_t[_y] = r_t[_x];    }    heap[_y] = merge(heap[_x],heap[_y]);    x[_y] += x[_x];    o[_y] += o[_x];}int main(){    int t;    cin >> t;    for(int ii = 1; ii <= t; ii++)    {        ans = cnt = tot = 0;        cin >> n >> m;        memset(heap,0,sizeof(heap));        memset(o,0,sizeof(o));        memset(x,0,sizeof(x));        int _x,_y,_z,_h;        l_b[1] = INF;        r_b[n] = INF;        l_t[n] = n-1;        for(int i = 1 ; i < n; i++)        {            scanf("%d",&_x);            l_b[i+1] = r_b[i] = _x;<span style="white-space:pre"></span>//合并时需要的信息            l_t[i] = i - 1;            r_t[i] = i + 1;        }        for(int i = 0; i < m; i++)        {            scanf("%d%d%d",&_x,&_y,&_z);            if(_z == 0)            {                ans++;                heap[_x] = heap[_x] ? insert(heap[_x],_y) : init(_y);            }            else            {                cnt++;                q[cnt].x = _x;                q[cnt].y = _y + 1;            }        }        for(int i = 1; i <= n; i++)            fa[i] = i;        sort(q+1,q+1+cnt);        for(int i = 1; i <= cnt; i++)        {            _h = q[i].y;            _x = q[i].x;            _x = getfa(_x);            while(_h > l_b[_x])            {                mergeSet(l_t[_x],_x);                _x = getfa(_x);            }            while(_h > r_b[_x])            {                mergeSet(r_t[_x],_x);                _x = getfa(_x);            }            while(heap[_x] && top(heap[_x]) < _h) {   //x,o数组统计无水 有水询问的和                heap[_x] = pop(heap[_x]);                x[_x]++;            }            o[_x]++;            if(o[_x] >= x[_x]) {                ans += (o[_x] - x[_x]);                o[_x] = x[_x] = 0;            }        }        printf("Case #%d: %d\n",ii,ans);    }    return 0;}


0 0
原创粉丝点击