您的位置:首页 > 其它

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

2016-08-10 15:10 295 查看
不妨假定初始答案为所有的无水询问,因为这样一定没有冲突。

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

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

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

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

#include <bits/stdc++.h>

using namespace std;

#define N 100010
#define INF INT_MAX
int n,m,l_b
,r_b
,l_t
,r_t
,x
,o
;

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
;

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
= INF;
l_t
= 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: