zoukankan      html  css  js  c++  java
  • HDU 5575 Discover Water Tank(左偏树)

    https://vjudge.net/problem/HDU-5575

    题意:

    有一个水箱,被n-1块板子分成了n个部分,板子的高度不尽相同。现在有m次探测,每次探测在第x部分的y+0.5高度处是否有水,回答0代表没水,1代表有水。现在要求出这m次探测最多有多少次是正确的。

    思路:

    挺难的一道题目吧。

    一开始如果把水箱当成空的,那么所有的无水探测就都是真的,至于有水探测的话,接下来我们可以一点一点的加水,这就要求将有水探测排序。每个部分可能会有多个无水探测(比如在第1部分,它进高度为1、3、5的地方都进行无水探测),那么在被淹没的时候肯定最先淹没高度为1的地方。这样的话,对于每个部分都可以建立一个优先队列,每次弹出值最小的。但是这些部分还会因为淹没而变成一部分,这时候要将两个部分的优先队列合并起来,这样的话,就是一个左偏树了。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<vector>
      4 #include<cstring>
      5 #include<algorithm>
      6 using namespace std;
      7 
      8 typedef pair<int,int> pll;
      9 const int INF = 0x3f3f3f3f;
     10 const int maxn = 1e5 + 5;
     11 
     12 int n,m,ans,tot;
     13 int LH[maxn],RH[maxn],L[maxn],R[maxn];
     14 int heap[maxn];
     15 int ok[maxn],nok[maxn],p[maxn];
     16 
     17 vector<pll> query;
     18 
     19 struct node
     20 {
     21     int l,r,dis,key;
     22 }t[2*maxn];
     23 
     24 int initHeap(int x)
     25 {
     26     t[++tot].key = x;
     27     t[tot].l = t[tot].r = t[tot].dis = 0;
     28     return tot;
     29 }
     30 
     31 int merge(int x, int y)
     32 {
     33     if(x == 0)  return y;
     34     if(y == 0)  return x;
     35     if(t[x].key>t[y].key)  swap(x,y);
     36     t[x].r = merge(t[x].r,y);
     37     if(t[t[x].l].dis < t[t[x].r].dis)  swap(t[x].l,t[x].r);
     38     if(t[x].r==0)  t[x].dis = 0;
     39     else t[x].dis = t[t[x].r].dis + 1;
     40     return x;
     41 }
     42 
     43 int insert(int x, int y)
     44 {
     45     return merge(x,initHeap(y));
     46 }
     47 
     48 int pop(int x)
     49 {
     50     return merge(t[x].l,t[x].r);
     51 }
     52 
     53 int finds(int x)
     54 {
     55     return x==p[x]?x:p[x]=finds(p[x]);
     56 }
     57 
     58 void unions(int x, int y)
     59 {
     60     x = finds(x);
     61     y = finds(y);
     62     if(x==y) return;
     63 
     64     p[y] = x;
     65     if(x>y)  //合并两个部分
     66     {
     67         LH[x] = LH[y];  
     68         L[x] = L[y];
     69     }
     70     else
     71     {
     72         RH[x] = RH[y];
     73         R[x] = R[y];
     74     }
     75 
     76     heap[x] = merge(heap[x],heap[y]);  //合并两个部分的左偏树
     77     ok[x] += ok[y];
     78     nok[x] += nok[y];
     79 }
     80 
     81 int main()
     82 {
     83     //freopen("in.txt","r",stdin);
     84     int T;
     85     scanf("%d",&T);
     86     int kase = 0;
     87     while(T--)
     88     {
     89         query.clear();
     90         memset(heap,0,sizeof(heap));
     91 
     92         scanf("%d%d",&n,&m);  
     93         LH[1] = RH[n] = INF;
     94         for(int i=1;i<n;i++)
     95         {
     96             scanf("%d",&RH[i]);
     97             LH[i+1] = RH[i];
     98             L[i] = i-1;  //i的左边
     99             R[i] = i+1;  //i的右边
    100         }
    101         L[n]=n-1;
    102         ans = tot = 0;
    103         while(m--)
    104         {
    105             int x,y,z;
    106             scanf("%d%d%d",&x,&y,&z);
    107             if(z==0)
    108             {
    109                 if(heap[x]==0)  heap[x] = initHeap(y);
    110                 else heap[x] = insert(heap[x],y);
    111                 ans++;
    112             }
    113             else
    114             {
    115                 query.push_back(make_pair(y,x));
    116             }
    117         }
    118         sort(query.begin(),query.end());
    119         for(int i=1;i<=n;i++)  ok[i]=nok[i]=0;
    120         for(int i=1;i<=n;i++)  p[i] = i;
    121         for(int i=0;i<query.size();i++)
    122         {
    123             int x = finds(query[i].second);
    124             int y = query[i].first;
    125             while(y>LH[x]) unions(x,L[x]);  //向左溢出
    126             while(y>RH[x]) unions(x,R[x]);  //向右溢出
    127             while(heap[x]!=0 && t[heap[x]].key<y)
    128             {
    129                 heap[x] = pop(heap[x]);
    130                 nok[x]++;
    131             }
    132             ok[x]++;  //当前进行的是真
    133             if(ok[x]>=nok[x])
    134             {
    135                 ans+=ok[x]-nok[x];
    136                 ok[x] = nok[x] = 0;
    137             }
    138         }
    139         printf("Case #%d: %d
    ",++kase,ans);
    140     }
    141     return 0;
    142 }
  • 相关阅读:
    区别是否是 微信浏览器 ?
    添加收藏
    函数调用那点事
    移动端返回上一页,刚需!document.referrer 详解
    蓝桥杯-乘积尾零
    printf不能直接输出string类型
    bitset的简单用法
    to_string()函数(C++)
    蓝桥杯-明码
    手写C语言字符库
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7849543.html
Copyright © 2011-2022 走看看