解法一:我们将沿y轴的线段按x从小到大排序,接着离散化,用线段树维护相邻两线段之间y的最大值,将每个点(当前x的坐标,x所在线段的最大值)存入list中,删
除中间不必要的点,然后输出所有点(首尾点要自己先行输出),详见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<list>
using namespace std;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
const int MAXN=400000+100;
int n,cnt;
int G[MAXN],ans_x[MAXN],ans_y[MAXN];
map<int,int>mp;
list<pair<int,int> >lis;
list<pair<int,int> >::iterator it;
struct Line
{
int y;
int x1,x2;
}line[MAXN];
struct node
{
int l,r;
int Max;
}segtree[MAXN<<2];
void init()
{
cnt=0;
memset(G,0,sizeof(G));
mp.clear();
lis.clear();
}
void build(int rt,int l,int r)
{
segtree[rt].l=l; segtree[rt].r=r; segtree[rt].Max=0;
if(l+1==r)
return ;
int mid=(l+r)>>1;
build(L(rt),l,mid); build(R(rt),mid,r);
}
void push_down(int rt)
{
if(segtree[rt].l+1 == segtree[rt].r)
return ;
segtree[L(rt)].Max=max(segtree[rt].Max,segtree[L(rt)].Max);
segtree[R(rt)].Max=max(segtree[rt].Max,segtree[R(rt)].Max);
}
void update(int rt,int l,int r,int x)
{
if(segtree[rt].l==l && segtree[rt].r ==r ){
segtree[rt].Max=max(segtree[rt].Max,x);
return ;
}
push_down(rt);
if(l>=segtree[R(rt)].l)
update(R(rt),l,r,x);
else if(r<=segtree[L(rt)].r)
update(L(rt),l,r,x);
else {
int mid=(segtree[rt].l+segtree[rt].r)>>1;
update(L(rt),l,mid,x);
update(R(rt),mid,r,x);
}
}
int query(int rt,int p)
{
if(segtree[rt].l+1 == segtree[rt].r )
return segtree[rt].Max;
push_down(rt);
int mid=(segtree[rt].l+segtree[rt].r)>>1;
if(p<mid) //不能等于
return query(L(rt),p);
else
return query(R(rt),p);
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
//freopen("text.txt","r",stdin);
while(~scanf("%d",&n)){
init();
for(int i=1;i<=n;i++){
scanf("%d%d%d",&line[i].y,&line[i].x1,&line[i].x2);
G[++cnt]=line[i].x1; G[++cnt]=line[i].x2;
}
sort(G+1,G+cnt+1);
int m=unique(G+1,G+cnt+1)-(G+1);
for(int i=1;i<=m;i++) mp[G[i]]=i;
build(1,1,m);
for(int i=1;i<=n;i++)
update(1,mp[line[i].x1],mp[line[i].x2],line[i].y);
for(int i=1;i<=m;i++){
int ans=query(1,i);
lis.push_back(pair<int,int>(G[i],ans));
if(i+1<=m)
lis.push_back(pair<int,int>(G[i+1],ans));
}
for(it=lis.begin();it!=lis.end();){ // 删除
int ans1=it->second;
list<pair<int,int> >::iterator it1=it;
it1++; if(it1==lis.end()) break;
list<pair<int,int> >::iterator it2=it1;
it2++; if(it2==lis.end()) break;
int ans2=it2->second;
if(ans1==ans2){
lis.erase(it1);
continue;
}
it++;
}
int top=0;
ans_x[top]=G[1]; ans_y[top++]=0;
for(it=lis.begin();it!=lis.end();it++){
ans_x[top]=it->first; ans_y[top++]=it->second;
list<pair<int,int> >::iterator it1=it;
it1++;
if(it1 == lis.end()) continue;
if(it1->first == it->first) continue;
}
it=lis.end();it--;
ans_x[top]=it->first ,ans_y[top++]=0;
printf("%d\n",top);
for(int i=0;i<top;i++)
printf("%d %d\n",ans_x[i],ans_y[i]);
}
return 0;
}
解法二: multiset维护最大值,用do while 处理所有v里x轴坐标为x的点对,之后只有当高度最大值发生变化时再向vector添加点,详见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
int n;
multiset<int> s;
vector<pair<int,int> > v,w;
vector<pair<int,int> >:: const_iterator it,it1;
void init()
{
s.clear();
v.clear(); w.clear();
}
int main()
{
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
while(~scanf("%d",&n))
{
init();
int y,x1,x2;
for(int i=0;i<n;i++){
scanf("%d%d%d",&y,&x1,&x2);
v.push_back(make_pair(x1,y));
v.push_back(make_pair(x2,-y));
}
sort(v.begin(),v.end());
int h;
s.insert(h=0); //放入初始高度
it=v.begin();
while(it!=v.end()){
it1=it;
do{
if(it1->second > 0)
s.insert(it1->second);
else if(it1->second<0) //second<0,则将对应高度在multiset中删除
s.erase(s.find(-it1->second));
it1++;
}while(it1!=v.end() && it1->first == it->first); //处理完所有first=it->first的v里的点对
if(*s.rbegin()!=h){ //最高高度发生变化,向w里添加点对
w.push_back(make_pair(it->first,h));
w.push_back(make_pair(it->first,h=*s.rbegin()));
}
it=it1;
}
printf("%d\n",w.size());
for (int i = 0; i < (int)w.size(); ++i)
printf("%d %d\n", w[i].first, w[i].second);
}
return 0;
}