题意:一个底面1*n的容器,两边无限高,中间被n-1块板阻断,给你m次观测,每次观测告诉你第i个区域是否有水,问你这些观测中最多有几个是对的。
思路:如果水超过板的高度,那么板的两边的区间就可以视为一个区间。所以只要枚举水没有溢出和水已经溢出这两种状态。我们从低到高的角度遍历板子,每次处理好这种状态,然后把这两个区间合并成一个区间,最后合并成一个区间,取一个最大值即可。我们把每个区域的观测存到一个堆中,当枚举到第i个板子时,把两边低于板高的观测取出,然后合并堆就好了。
开始不会可并堆,然后去学了一波左斜树,后来lxw告诉我__gnu_pbds有封装好的。。。
pbds版:
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define pb push_back
#define pa pair<int,int>
#define N 200005
pa a[N];
int f[N];
int dp[N][2];
int finds(int x){return x==f[x]?x:f[x]=finds(f[x]); }
int get(int x,int y){
int w=dp[x][1];
while(!q[x].empty()){
pa p=q[x].top();
if(p.first>y)break;
w+=p.second;
dp[x][0]=max(dp[x][0],w);
q[x].pop();
}
return w;
}
int main()
{
int T,cas=1,n,m,id,h,fl;
cin>>T;
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
scanf("%d",&a[i].first);
a[i].second=i;
}
for(int i=1;i<=n;i++)f[i]=i,dp[i][0]=dp[i][1]=0;
sort(a+1,a+n);
for(int i=1;i<=m;i++){
scanf("%d %d %d",&id,&h,&fl);
q[id].push(pa(h+1,fl==1?1:-1));
if(!fl)dp[id][0]++,dp[id][1]++;
}
int ans=0,w;
for(int i=1;i<n;i++){
int fx=finds(a[i].second),fy=finds(a[i].second+1);
dp[fy][1]=get(fx,a[i].first)+get(fy,a[i].first);
dp[fy][0]=dp[fx][0]+dp[fy][0];
f[fx]=fy;q[fy].join(q[fx]);
}
int x=finds(1);
dp[x][1]=get(x,1e9+7);
printf("Case #%d: %d\n",cas++,max(dp[x][0],dp[x][1]));
}
return 0;
}
左斜树版:
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define pb push_back
#define pa pair<int,int>
#define N 200005
__gnu_pbds::priority_queue<pa,greater<pa> >q[N];
int c[N],rs[N],ls[N],dis[N],d[N],tot=0,he[N];
int New(int x,int y){
c[tot]=x;d[tot]=y;
ls[tot]=rs[tot]=dis[tot]=0;
return tot++;
}
int Merge(int a,int b){
if(!a||!b)return a+b;
if(c[a]>c[b])swap(a,b);
rs[a]=Merge(rs[a],b);
if(dis[ls[a]]<dis[rs[a]])swap(ls[a],rs[a]);
dis[a]=dis[rs[a]]+1;
return a;
}
int pop(int a){return Merge(ls[a],rs[a]);}
pa a[N];
int f[N];
int dp[N][2];
int finds(int x){return x==f[x]?x:f[x]=finds(f[x]); }
int get(int x,int y){
int w=dp[x][1];
while(he[x]!=0){
if(c[he[x]]>y)break;
w+=d[he[x]];
dp[x][0]=max(dp[x][0],w);
he[x]=pop(he[x]);
}
return w;
}
int main()
{
int T,cas=1,n,m,id,h,fl;
cin>>T;
while(T--){
scanf("%d%d",&n,&m);
tot=1;
for(int i=1;i<n;i++){
scanf("%d",&a[i].first);
a[i].second=i;
}
for(int i=1;i<=n;i++)f[i]=i,dp[i][0]=dp[i][1]=0,he[i]=0;
sort(a+1,a+n);
for(int i=1;i<=m;i++){
scanf("%d %d %d",&id,&h,&fl);
he[id]=!he[id]?New(h+1,fl?1:-1):Merge(he[id],New(h+1,fl?1:-1));
if(!fl)dp[id][0]++,dp[id][1]++;
}
int ans=0,w;
for(int i=1;i<n;i++){
int fx=finds(a[i].second),fy=finds(a[i].second+1);
dp[fy][1]=get(fx,a[i].first)+get(fy,a[i].first);
dp[fy][0]=dp[fx][0]+dp[fy][0];
f[fx]=fy;he[fy]=Merge(he[fx],he[fy]);
}
int x=finds(1);
dp[x][1]=get(x,1e9+7);
printf("Case #%d: %d\n",cas++,max(dp[x][0],dp[x][1]));
}
return 0;
}