Codeforces 269D. Maximum Waterfall解题报告
点击这里进入题目
题意:在一面墙上有几块木板,给你木板在前面上的高度,左端点,右端点,你可以控制水流的方向,水流能从上面的木板流向下面的木板需要两个木板在高度上有相交以及中间没木板隔开,问最大的水流量。
思路:先用一个vector,将左端点和右端点拆开记录,同时标清楚是哪一块木板,高度在哪,以及是左端点还是右端点,然后按照从左到右的顺序排序。然后遍历这个vector,遇到左端点就将这块木板压入set中,set按照高度排序,然后找到当前木板的上一块木板以及下一块木板,将上一块木板连一条边到当前,将当前连一条边到下一块木板,如果上下已经相连,便要断开连接,同时记录从上到下能通过的最大水流量。建好图只好跑一遍记忆化的dfs,找到最下面一块木板的最大值就行了。(据说可以用线段树搞,但我没想出来)
AC程序
//库省略
using namespace std;
const long long maxn=100005,INF=2e9;
vector<long long> g[maxn],c[maxn];
long long l[maxn],r[maxn],ans[maxn];
long long n,t;
struct st
{
long long hi,pos;
bool flag;
long long id;
};
st ll;
st rr;
vector<st> ev;
bool cmp(st a,st b)
{
if(a.pos!=b.pos)
return a.pos<b.pos;
if(a.flag!=b.flag)
return a.flag<b.flag;
return a.id<b.id;
}
int cal(int a,int b)
{
return (min(r[a],r[b])-max(l[a],l[b]));
}
long long dfs(int x)
{
if(ans[x]!=-1)
return ans[x];
if(x==1)
return INF;
ans[x]=0;
for(int i=0;i<g[x].size();i++)
ans[x]=max(ans[x],min(c[x][i],dfs(g[x][i])));
return ans[x];
}
int main()
{
cin>>n>>t;
n+=2;
for(int i=2;i<n;i++)
{
int hi;
cin>>hi>>l[i]>>r[i];
rr.hi=hi;rr.pos=r[i];rr.flag=0;rr.id=i;
ll.hi=hi;ll.pos=l[i];ll.flag=1;ll.id=i;
ev.pb(rr);
ev.pb(ll);
}
sort(ev.begin(),ev.end(),cmp);
set<pair<long long,long long> > s;
s.clear();
s.insert(mp(t,0));
s.insert(mp(0,1));
l[0]=l[1]=-(1<<30);
r[0]=r[1]=(1<<30);
for(int i=0;i<ev.size();i++)
{
if(!ev[i].flag)
{
s.erase(mp(ev[i].hi,ev[i].id));
}
else
{
set<pair<long long,long long> >::iterator iter=s.insert(mp(ev[i].hi,ev[i].id)).first;
int down=(--iter)->second;
iter++;
int up=(++iter)->second;
if(g[up].size() && g[up].back()==down)
{
g[up].pop_back();
c[up].pop_back();
}
g[up].pb(ev[i].id);
c[up].pb(cal(ev[i].id,up));
g[ev[i].id].pb(down);
c[ev[i].id].pb(cal(ev[i].id,down));
}
}
memset(ans,-1,sizeof(ans));
cout<<dfs(0)<<endl;
return 0;
}