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\n",++kase,ans);
140     }
141     return 0;
142 }

 

posted @ 2017-11-17 08:16  Kayden_Cheung  阅读(425)  评论(0编辑  收藏  举报
//目录