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 }