2015 上海区域赛 D Discover water tank 并查集dp+左偏树

原创 2016年05月31日 22:20:49
题意:

这个博客上说的都很清楚,不再多说

感觉这道题可以命名为并查集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();
    }

}





版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU5575 Discover Water Tank 2015上海现场赛D题 (树形dp,并查集,左偏树)

题目大意: 有一个1维的长度为N,高度无限的水柜,现在要用N-1个挡板将其分为N个长度为1的小格,然后向水柜中注水,水可以低于挡板也可以以溢出去(这样就要与旁边格子的水位相同),现在有M次探测,探测...
  • qq_19592437
  • qq_19592437
  • 2015年12月10日 17:17
  • 2263

2015年南海区初中信息学竞赛试题解题报告

第一题 危险的实验(dangerous) 【题意分析】 将n个化学物质放在桌子上,给出它们与附近化学物质的安全距离,请问最短需要多长的桌子。 【数据范围】 20%的数据,1 50%的数据,1 100%...
  • Wmwl1345
  • Wmwl1345
  • 2016年08月04日 20:24
  • 1089

2015年ACM上海大都会邀请赛总结

更新记录H题成功拿到HDU static rank1!(我TM是有多闲。。) 已经完成赛后AK!可喜可贺!虽然这个AK的周期略长。。都是我太弱。。 比赛经历非常神奇的一场比赛,两百多个队在一个体...
  • Zava_1087
  • Zava_1087
  • 2015年05月27日 04:38
  • 4396

详细的数据结构延伸介绍(包括AC自动机SBT,伸展树,字典树,并查集,笛卡尔树,二叉堆,斐波那契堆,哈希表,红黑树,后缀树,后缀数组,树状数组,线段树,左偏树,斜堆)

  • 2010年12月12日 20:57
  • 19.07MB
  • 下载

HDU 1512 (左偏树 并查集)

题意:有n只猴子,每只猴子都有一个能力值.最初每只猴子都只认识自己.然后 给出m组询问,每次都有两只猴子,如果他们相互认识输出-1,否则他们会请出他们认 识的猴子中能力值最大的猴子,这两只猴子自身...
  • morejarphone
  • morejarphone
  • 2016年05月27日 15:14
  • 306

ZOJ2334 Monkey King 左偏树+并查集

有一n个猴子,每个猴子有一个战斗力,如果x和y不认识那么x会找他认识的猴子中战斗力最高的猴子与y认识的猴子中战斗力最高的猴子打一架,然后两只打架的猴子战斗力减半,然后x认得所有猴子就和y认识的所有猴子...
  • u010839163
  • u010839163
  • 2014年07月27日 00:23
  • 338

HDU 1512 浅谈可并堆即左偏树模板及并查集灵活应用

世界真的很大 若要学可并堆的话,这道题是个比较裸的题了 可并堆的话左偏树算是比较常用的了 好写好调 看一下题先: description有n只猴子,每只猴子有厉害值,一开始素不相识。 两只不...
  • BerryKanry
  • BerryKanry
  • 2017年07月17日 08:32
  • 117

HDU 1512 Monkey King(左偏树+并查集)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1512 题       意: 有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表...
  • Seraphimon
  • Seraphimon
  • 2015年07月27日 19:05
  • 363

HDU 1512 Monkey King 左偏树 + 并查集

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1512 题意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害...
  • discreeter
  • discreeter
  • 2016年07月12日 14:54
  • 409

zoj2334 Monkey King , 并查集,可并堆,左偏树

提交地址:点击打开链接 题意:  N(N 分析:涉及集合的查询,合并,取最值。 利用并查集和左偏树即可解决。 #include #include #include #include u...
  • yew1eb
  • yew1eb
  • 2014年07月13日 10:15
  • 1829
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:2015 上海区域赛 D Discover water tank 并查集dp+左偏树
举报原因:
原因补充:

(最多只允许输入30个字)