2015 上海区域赛 D Discover water tank 并查集dp+左偏树
来源:互联网 发布:淘宝男装图片 编辑:程序博客网 时间:2024/04/29 19:27
题意:
实际上优先队列的三个操作都是这么实现的
这个博客上说的都很清楚,不再多说
感觉这道题可以命名为并查集dp
包括题解也是,具体解释一下左偏树的使用。
左偏树,说白了就是可合并优先队列,你有两个优先队列,那么怎么才能让他合并成一个呢,stl库的优先队列是做不到的,只能手动实现左偏树,这种数据结构可以实现在o(logn)的时间内合并两个优先队列
int merge(int a, int b) { if (!a)return b; else if (!b)return a; if (query[a].first > query[b].first)swap(a, b); r[a] = merge(r[a], b); if (dist[r[a]] > dist[l[a]])swap(l[a], r[a]); if (!r[a]) dist[a] = 0; else dist[a] = dist[r[a]] + 1; return a;}//左偏树合并操作,代表把下标为a的查询所在的左偏树和下标为b的查询所在的左偏树合并起来
实际上优先队列的三个操作都是这么实现的
1. pop 取队头操作:把要取的树的a = merge(l[a], r[a])即可
2. push 插入操作: a = merge(a, new)
3. 合并两个树操作 a = merge( u, v )
/*hdu 5575*/#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#include <queue>#include <vector>#include <iostream>#define pii pair<int,int>#define xx first#define yy second#define mem(a) memset( a, 0, sizeof(a) )using namespace std;typedef long long ll;int l[200005];int r[200005];pii query[200005];//int dist[200005];int fa[100005];pii ban[100005];vector<pii>s;int n, m;int merge(int a, int b) { if (!a)return b; else if (!b)return a; if (query[a].first > query[b].first)swap(a, b); r[a] = merge(r[a], b); if (dist[r[a]] > dist[l[a]])swap(l[a], r[a]); if (!r[a]) dist[a] = 0; else dist[a] = dist[r[a]] + 1; return a;}//左偏树合并操作,代表把下标为a的查询所在的左偏树和下标为b的查询所在的左偏树合并起来struct node{ int qe, h, out, in;// out 溢出最优解 in 未溢出最优解 qe 指向该区域内高度最低的查询}p[100005];int root( int x ){ if( fa[x] == x ) return x; else return fa[x] = root(fa[x]);}void getup( int id, int he ){ int i, j, in_max = 0, out_max = 0, tmp = 0; s.clear(); while( p[id].qe && query[p[id].qe].xx < he ){ s.push_back(query[p[id].qe]); if( query[p[id].qe].yy == 0 ) in_max ++; p[id].qe = merge( l[p[id].qe], r[p[id].qe] );// pop队首操作 } sort( s.begin(), s.end() ); tmp = in_max;// 相当于从水底向水高扫一遍,水高停在哪里是最优解(此为未溢出) out_max = in_max; for( i = 0; i < s.size(); i ++ ){ if( i && s[i].xx != s[i-1].xx ){ out_max = max( out_max, tmp ); } if( s[i].yy ) tmp ++; else tmp --; } out_max = max( out_max, tmp ); p[id].in = max( p[id].in + in_max, p[id].out + out_max ); // 由 之前没溢出现在也没溢出 和之前溢出现在没溢出更新而来 p[id].out = p[id].out + tmp; p[id].h = he;}void mrg( int p1, int p2, int he ){ int f1, f2; f1 = root(p1); f2 = root(p2); if( p[f1].h < he ) getup( f1, he ); if( p[f2].h < he ) getup( f2, he ); fa[f2] = f1; p[f1].qe = merge( p[f1].qe, p[f2].qe ); p[f1].in += p[f2].in; p[f1].out += p[f2].out;}void solve(){ int i, j; cin >> n >> m; mem(l); mem(r); mem(dist); mem(p); for( i = 1; i <= n; i ++ )fa[i] = i; for( i = 1; i <= n-1; i ++ ){ scanf("%d", &ban[i].xx); ban[i].yy = i; } for( i = 1; i <= m; i ++ ){ scanf("%d %d %d", &j, &query[i].xx, &query[i].yy); p[j].qe = merge( p[j].qe, i ); } sort( ban+1, ban+n ); for( i = 1; i <= n-1; i ++ ){ mrg( ban[i].yy, ban[i].yy+1, ban[i].xx ); } int ff = root(1); getup( ff, 1e9+7 );// 最后把水上升到无线高 cout << p[ff].in << endl;}int main(){ int T, cas = 1, i, j; cin >> T; while( T -- ){ printf("Case #%d: ", cas ++); solve(); }}
0 0
- 2015 上海区域赛 D Discover water tank 并查集dp+左偏树
- 树形DP+并查集+左偏树, HDU-5575,Discover Water Tank,2015上海现场赛D题
- HDU5575Discover Water Tank 2015上海现场赛D题 (树形dp,并查集,左偏树)
- HDU 5575 Discover Water Tank 并查集+左偏树
- HDU 5575 Discover Water Tank(并查集+左偏树/启发式合并)
- HDU 5575 Discover Water Tank
- HDU-5575-Discover Water Tank
- [Shanghai2015]Discover Water Tank解题报告
- hdu5443The Water Problem 并查集
- 2015年长春区域网络赛 hdu 5441 Travel【并查集】
- 2015 上海区域赛 Friendship of Frog
- 2015 上海区域赛 部分题解
- 并查集练习---poj 1417 并查集+DP
- MUTC 2 D - Matrix 并查集
- HDU 4496 D-City(并查集)
- hdu(4996) D-City 并查集
- Codeforces 366D 贪心+并查集
- hdu 4496 D-City 并查集
- #VSTS日志# Xamarin构建支持和一大波更新
- 34Search for a Range
- dp 略难 poj1661
- 向android studio中添加Genymotion
- Vim心得
- 2015 上海区域赛 D Discover water tank 并查集dp+左偏树
- CodeForces-13A-Numbers
- C#实现http多线程断点续传下载文件
- UDAD 用户故事驱动的敏捷开发 – 演讲实录
- xcode中prefixHeader.pch文件找不到怎么解决?
- miniblink支持font 图标了
- Java ClassLoader 原理详细分析
- 新的开始
- Create a device node in code