码迷,mamicode.com
首页 > 其他好文 > 详细

有趣的凸壳问题~

时间:2014-08-19 20:34:25      阅读:2301      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   http   color   os   io   strong   

PART I  BZOJ 1249

 

1249: SGU277 HERO 动态凸包

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 406  Solved: 123
[Submit][Status]

Description

平面上最开始只包含3个点,然后还会依次出现N个点。每新增一个点,请你求出包含这些点的周长最小的多边形的面积(也就是凸包的面积)。

Input

第一行为6个整数,表示最初的三个点的坐标(x1,y1),(x2,y2),(x3,y3)。 第二行仅一个数N。 以下N行,每行两个整数(xi,yi),表示新增的点的坐标。

Output

对于每次新增点的操作,请你输出新增完此点后当前的凸包的面积的两倍。

Sample Input

0 0 0 2 2 0
3
2 2
1 1
2 4

Sample Output

8
8
12

HINT

N<=100000
点的坐标巨大,目测在[-10^9,10^9]

 

 

支持插入操作的凸包。每次插入以后求出凸包面积。

 

还记得Graham水平扫描法吗?我们分别维护上凸壳和下凸壳,同时更新面积。

 

假如维护上凸壳,新增点P(X,Y),找到相邻两点使得Xi<X<Xj,当且仅当向量P→Pj 在Pi→P的顺时针方向,点P插在凸壳上。

 

顺时针<==>cross(PiP,PPj)<0,叉积就点到为止。

 

若插入,向左维护向右维护。

 

下凸壳反之。

 

 

bubuko.com,布布扣
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define MAXN 100010
using namespace std;
typedef long long LL;
LL n,area,sum; 
   
struct point{
    LL x,y;
    bool operator<(const point&b)const{
        return (x<b.x||x==b.x&&y<b.y);
    }
    point operator-(const point&b)const{
        return (point){x-b.x,y-b.y};
    }
};
typedef point vector;
set<point>U,D;
set<point>::iterator l,r,it;
   
LL sqr(LL x){return x*x;}
   
LL cross(vector a,vector b){
    return a.x*b.y-b.x*a.y;
}
   
void maintain_U(point p){
    it=U.lower_bound(p);
    if(it==U.begin()){
        r=it;it++;
        while(it!=U.end()){
            if(cross(*r-p,*it-p)<0) break;
            sum+=cross(*r,*it);
            U.erase(r);r=it;it++;
        }
        sum-=cross(p,*r);
        U.insert(p);
    }else if(it==U.end()){
        it--;l=it;
        while(it!=U.begin()){
            it--;if(cross(*l-*it,p-*it)<0) break;
            sum+=cross(*it,*l);
            U.erase(l);l=it; 
        }
        sum-=cross(*l,p);
        U.insert(p);
    }else{
       r=it;it--;l=it;
        if(cross(p-*l,*r-*l)<0){
            sum+=cross(*l,*r);
            while(it!=U.begin()){
                it--;if(cross(*l-*it,p-*it)<0) break;
                sum+=cross(*it,*l);
                U.erase(l);l=it; 
            }
            sum-=cross(*l,p);
            it=r;it++;
            while(it!=U.end()){
                if(cross(*r-p,*it-p)<0) break;
                sum+=cross(*r,*it);
                U.erase(r);r=it;it++;
            }
            sum-=cross(p,*r);
            U.insert(p);            
        }
    }
}
   
void maintain_D(point p){
    it=D.lower_bound(p);
    if(it==D.begin()){
        r=it;it++;
        while(it!=D.end()){
            if(cross(*r-p,*it-p)>0) break;
            sum-=cross(*r,*it);
            D.erase(r);r=it;it++;
        }
        sum+=cross(p,*r);
        D.insert(p);
    }else if(it==D.end()){
        it--;l=it;
        while(it!=D.begin()){
            it--;if(cross(*l-*it,p-*it)>0) break;
            sum-=cross(*it,*l);
            D.erase(l);l=it; 
        }
        sum+=cross(*l,p);
        D.insert(p);
    }else{
        r=it;it--;l=it;
        if(cross(p-*l,*r-*l)>0){
            sum-=cross(*l,*r);
            while(it!=D.begin()){
                it--;if(cross(*l-*it,p-*it)>0) break;
                sum-=cross(*it,*l);
                D.erase(l);l=it; 
            }
            sum+=cross(*l,p);
            it=r;it++;
            while(it!=D.end()){
                if(cross(*r-p,*it-p)>0) break;
                sum-=cross(*r,*it);
                D.erase(r);r=it;it++;
            }
            sum+=cross(p,*r);
            D.insert(p);            
        }
    }
}
   
int main(){
    //freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
    point p1,p2,p3,p;
    scanf("%lld%lld%lld%lld%lld%lld",&p1.x,&p1.y,&p2.x,&p2.y,&p3.x,&p3.y);
    if(p2<p1) swap(p1,p2);
    if(p3<p1) swap(p1,p3);
    if(p3<p2) swap(p2,p3);
    U.insert(p1);D.insert(p1);
    U.insert(p3);D.insert(p3);
    area=cross(p2-p1,p3-p1);
    if(area<0) U.insert(p2),sum-=area;
    if(area>0) D.insert(p2),sum+=area;
    scanf("%d",&n);
    while(n--){
        scanf("%lld%lld",&p.x,&p.y);
        maintain_U(p);
        maintain_D(p);
        printf("%lld\n",sum);
    }
    return 0;
}
BZOJ1249

 

 

PART II  BZOJ 2300

2300: [HAOI2011]防线修建

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 394  Solved: 191
[Submit][Status]

Description

 

近来A国和B国的矛盾激化,为了预防不测,A国准备修建一条长长的防线,当然修建防线的话,肯定要把需要保护的城市修在防线内部了。可是A国上层现在还犹豫不决,到底该把哪些城市作为保护对象呢?又由于A国的经费有限,所以希望你能帮忙完成如下的一个任务:

1.      给出你所有的A国城市坐标

2.      A国上层经过讨论,考虑到经济问题,决定取消对i城市的保护,也就是说i城市不需要在防线内了

3.      A国上层询问对于剩下要保护的城市,修建防线的总经费最少是多少

 

你需要对每次询问作出回答。注意单位1长度的防线花费为1。

 

A国的地形是这样的,形如下图,x轴是一条河流,相当于一条天然防线,不需要你再修建

A国总是有两个城市在河边,一个点是(0,0),一个点是(n,0),其余所有点的横坐标均大于0小于n,纵坐标均大于0。A国有一个不在(0,0)和(n,0)的首都。(0,0),(n,0)和首都这三个城市是一定需要保护的。

 bubuko.com,布布扣

 

上图中,A,B,C,D,E点为A国城市,且目前都要保护,那么修建的防线就会是A-B-C-D,花费也就是线段AB的长度+线段BC的长度+线段CD的长度

如果,这个时候撤销B点的保护,那么防线变成下图

  bubuko.com,布布扣

Input

第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。

第二行,一个整数m。

接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。

再接下来一个整数q,表示修改和询问总数。

接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。

Output

对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数

 

Sample Input

4 2 1
2
1 2
3 2
5
2
1 1
2
1 2
2


Sample Output

6.47
5.84
4.47

HINT

 数据范围:

30%的数据m<=1000,q<=1000

100%的数据m<=100000,q<=200000,n>1

所有点的坐标范围均在10000以内, 数据保证没有重点

 

 

支持删除操作的凸包。求出每次删除以后的凸包周长。没有强制在线。

 

做法很显然,离线,从后往前逐个插入。维护上凸壳即可。

 

bubuko.com,布布扣
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<set>
  8 #define MAXN 200010
  9 using namespace std;
 10 double sum;
 11 int op[MAXN],t[MAXN],vis[MAXN];double ans[MAXN];
 12 
 13 struct point{
 14     int x,y;
 15     bool operator<(const point&b)const{
 16         return (x<b.x||x==b.x&&y<b.y);
 17     }
 18     point operator-(const point&b)const{
 19         return (point){x-b.x,y-b.y};
 20     }
 21 }p[MAXN];
 22 typedef point vector;
 23 set<point>U;
 24 set<point>::iterator l,r,it;
 25 
 26 double sqr(double x){return x*x;}
 27 double dist(point a,point b){
 28     return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
 29 }
 30 int cross(vector a,vector b){
 31     return a.x*b.y-b.x*a.y;
 32 }
 33 
 34 void maintain_U(point p){
 35     it=U.lower_bound(p);
 36     if(it==U.begin()){
 37         r=it;it++;
 38         while(it!=U.end()){
 39             if(cross(*r-p,*it-p)<0) break;
 40             sum-=dist(*r,*it);
 41             U.erase(r);r=it;it++;
 42         }
 43         sum+=dist(p,*r);
 44         U.insert(p);
 45     }else if(it==U.end()){
 46         it--;l=it;
 47         while(it!=U.begin()){
 48             it--;if(cross(*l-*it,p-*it)<0) break;
 49             sum-=dist(*it,*l);
 50             U.erase(l);l=it; 
 51         }
 52         sum+=dist(*l,p);
 53         U.insert(p);
 54     }else{
 55         r=it;it--;l=it;
 56         if(cross(p-*l,*r-*l)<0){
 57             sum-=dist(*l,*r);
 58             
 59             while(it!=U.begin()){
 60                 it--;if(cross(*l-*it,p-*it)<0) break;
 61                 sum-=dist(*it,*l);
 62                 U.erase(l);l=it; 
 63             }
 64             sum+=dist(*l,p);
 65             
 66             it=r;it++; 
 67             while(it!=U.end()){
 68                 if(cross(*r-p,*it-p)<0) break;
 69                 sum-=dist(*r,*it);
 70                 U.erase(r);r=it;it++;
 71             }
 72             sum+=dist(p,*r);
 73             U.insert(p);        
 74         }
 75     }
 76 }
 77 
 78 int main(){
 79     freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
 80     int n,m,q,x,y;
 81     scanf("%d%d%d",&n,&x,&y);
 82     point A={0,0},B={n,0},C={x,y};
 83     U.insert(A);U.insert(B);U.insert(C);
 84     sum=dist(A,C)+dist(B,C);    
 85     
 86     scanf("%d",&m);
 87     for(int i=1;i<=m;i++) scanf("%d%d",&p[i].x,&p[i].y);
 88     
 89     memset(vis,0,sizeof(vis));
 90     scanf("%d",&q);
 91     for(int i=1;i<=q;i++){
 92         scanf("%d",&op[i]);
 93         if(op[i]==1){
 94             scanf("%d",&t[i]);
 95             vis[t[i]]=1;
 96         }
 97     }
 98     
 99     for(int i=1;i<=m;i++) if(!vis[i]) maintain_U(p[i]);
100     for(int i=q;i>=1;i--)
101         if(op[i]==1)
102             maintain_U(p[t[i]]);
103         else
104             ans[i]=sum;
105     for(int i=1;i<=q;i++)
106         if(op[i]==2)
107             printf("%.2lf\n",ans[i]); 
108     return 0;
109 }
BZOJ2300

 

 

PART III(简单应用) BZOJ 1492

1492: [NOI2007]货币兑换Cash

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 1542  Solved: 719
[Submit][Status]

Description

bubuko.com,布布扣

Input

第一行两个正整数N、S,分别表示小Y 能预知的天数以及初始时拥有的钱数。 接下来N 行,第K 行三个实数AK、BK、RateK,意义如题目中所述

Output

只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金钱 数目。答案保留3 位小数。

Sample Input

3 100
1 1 1
1 2 2
2 2 3

Sample Output

225.000

HINT

bubuko.com,布布扣

测试数据设计使得精度误差不会超过10-7。
对于40%的测试数据,满足N ≤ 10;
对于60%的测试数据,满足N ≤ 1 000;
对于100%的测试数据,满足N ≤ 100 000;

 

简要做法:
 
令F[i]表示第i天获得的最大B卷数量。
枚举上一次交易日j
F[i]=max{ans,Rate[j]*F[j]*A[i]+F[j]*B[i]}/(rate[i]*a[i]+b[i])
O(n^2)
 
观察括号内的表达式,可以发现决策J优于决策K的条件:(rate[j]*f[j]-rate[k]*f[k])/(f[j]-f[k])>-b[i]/a[i]
上面这个式子的左边,一般记成slope(j,k)

Slope(j,k) > -b[i]/a[i]

令G[i] = rate[i]*f[i],在二维平面上定义点Xi=(Fi,Gi)
Slope(j,k)就是通过Xj和Xk的斜率
 
维护一个点集X,支持以下两个操作:
?1)在第一象限的任意位置插入一个点
?2)给定负数斜率K,求所有斜率为K且过点集中任意点的直线在Y轴上的最大截距
操作2最终用到的点都会在点集的上凸壳上
?维护点集X的凸包,支持动态插入和斜率查询
?平衡树结构 O(nlogn)

 

很喜闻乐见的是,本题需要查询斜率,笔者太弱不会用set实现。splay维护凸壳模板题~

第一次写,代码很翔。

 

bubuko.com,布布扣
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<algorithm>
  7 #define eps 1e-7
  8 #define MAXN 100010
  9 #define LR ch[ch[root][0]][1]
 10 #define RL ch[ch[root][1]][0]
 11 #define INF 0x3f3f3f3f
 12 using namespace std;
 13 double a[MAXN],b[MAXN],rate[MAXN];
 14 double s,ans; int n;
 15 
 16 struct point{
 17     double x,y;
 18     bool operator<(const point&b)const{
 19         return (x<b.x||x==b.x&&y<b.y);
 20     }
 21     bool operator>(const point&b)const{
 22         return (x>b.x||x==b.x&&y>b.y);
 23     }
 24     point operator-(const point&b)const{
 25         return (point){x-b.x,y-b.y};
 26     }
 27 };
 28 typedef point vector;
 29 
 30 double sqr(double x){return x*x;}
 31 
 32 double dist(point a,point b){
 33     return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
 34 }
 35 
 36 double cross(vector a,vector b){
 37     return a.x*b.y-b.x*a.y;
 38 }
 39 
 40 struct Splay_ConvexHull{
 41     point key[MAXN];int pre[MAXN],suc[MAXN];
 42     int ch[MAXN][2],f[MAXN],queue[MAXN],pool[MAXN];
 43     int root,cnt,top;
 44     void clear(){
 45         root=cnt=top=0;
 46     }
 47     int newnode(point v,int fa){
 48         int x=top?pool[top--]:(++cnt);
 49         key[x]=v;f[x]=fa;ch[x][0]=ch[x][1]=0;
 50         return x;
 51     }
 52     void rotate(int x,int t){
 53         int y=f[x];
 54         f[x]=f[y];if(f[y]) ch[f[y]][ch[f[y]][1]==y]=x;
 55         ch[y][t]=ch[x][!t];if(ch[x][!t]) f[ch[x][!t]]=y;
 56         f[ch[x][!t]=y]=x;
 57     }
 58     void splay(int x,int goal){
 59         while(f[x]!=goal){
 60             if(f[f[x]]==goal){
 61                 rotate(x,ch[f[x]][1]==x);
 62             }else{
 63                 int y=f[x],t=(ch[f[y]][1]==y);
 64                 if(ch[y][t]==x) rotate(y,t),rotate(x,t);
 65                 else rotate(x,!t),rotate(x,t);
 66             }
 67         }
 68         if(goal==0) root=x;
 69     }
 70     void erase(int x){
 71         if(!x) return;
 72         int h=0,t=0;
 73         for(queue[t++]=x;h<t;h++){
 74             int v=queue[h];pool[++top]=v;
 75             if(ch[v][0]) queue[t++]=ch[v][0];
 76             if(ch[v][1]) queue[t++]=ch[v][1];
 77         }
 78     }
 79     void maintain(int x){
 80         int p;
 81         if(ch[x][0]){
 82             for(p=ch[x][0];ch[p][1];p=ch[p][1]);
 83             suc[p]=x;pre[x]=p;
 84         }else
 85             pre[x]=0;
 86         if(ch[x][1]){
 87             for(p=ch[x][1];ch[p][0];p=ch[p][0]);
 88             pre[p]=x;suc[x]=p;
 89         }else
 90             suc[x]=0;    
 91     }
 92     int _insert(point v){
 93         if(!root){
 94             root=newnode(v,0);pre[root]=suc[root]=0;
 95             return root;
 96         }
 97         int x=root;
 98         for(;ch[x][key[x]<v];x=ch[x][key[x]<v]);
 99         ch[x][key[x]<v]=newnode(v,x);
100         x=ch[x][key[x]<v];
101         splay(x,0);
102         maintain(x);
103         return x;
104     }
105     int getsuc(point v){
106         int x=root,ret=0;point min={INF,INF};
107         while(x){
108             if(!(key[x]<v)) if(key[x]<min) min=key[x],ret=x;
109             x=ch[x][key[x]<v];
110         }
111         return ret;
112     }
113     void maintain_U(point v){
114         int _=getsuc(v),p,x,y,t;
115         if(_)
116             if(pre[_]){
117                 if(cross(v-key[pre[_]],key[_]-key[pre[_]])>-eps) return;
118                 p=_insert(v);
119                 
120                 x=ch[p][1],y=p,t=1;
121                 while(x){
122                     if(suc[x]==0||(cross(key[x]-v,key[suc[x]]-v)<-eps)){
123                         f[ch[y][t]=x]=y;y=x;t=0;x=ch[x][0];
124                     }else{
125                         pool[++top]=x;erase(ch[x][0]);x=ch[x][1];
126                     }
127                 }
128                 ch[y][t]=0;
129                 
130                 x=ch[p][0],y=p,t=0;
131                 while(x){
132                     if(pre[x]==0||(cross(key[x]-key[pre[x]],v-key[pre[x]])<eps)){
133                         f[ch[y][t]=x]=y;y=x;t=1;x=ch[x][1];
134                     }else{
135                         pool[++top]=x;erase(ch[x][1]);x=ch[x][0];
136                     }
137                 }
138                 ch[y][t]=0;
139             }else{
140                 p=_insert(v);x=ch[p][1],y=p,t=1;
141                 while(x){
142                     if(suc[x]==0||(cross(key[x]-v,key[suc[x]]-v)<eps)){
143                         f[ch[y][t]=x]=y;y=x;t=0;x=ch[x][0];
144                     }else{
145                         pool[++top]=x;erase(ch[x][0]);x=ch[x][1];
146                     }
147                 }
148                 ch[y][t]=0;
149             }
150         else{
151             p=_insert(v);x=ch[p][0],y=p,t=0;
152             while(x){
153                 if(pre[x]==0||(cross(key[x]-key[pre[x]],v-key[pre[x]])<-eps)){
154                     f[ch[y][t]=x]=y;y=x;t=1;x=ch[x][1];
155                 }else{
156                     pool[++top]=x;erase(ch[x][1]);x=ch[x][0];
157                 }
158             }
159             ch[y][t]=0;
160         }
161         maintain(p);
162     }
163     int getpre_U(double slope){
164         int x=root,ret=0;
165         double dy=10000,dx=0.0001,ey,ex;
166         while(x){
167             if(pre[x]){
168             ey=key[x].y-key[pre[x]].y;ex=key[x].x-key[pre[x]].x;
169             if(ey>ex*slope){
170                 if(ey*dx<dy*ex){
171                     ret=x;dy=ey;dx=ex;
172                 }
173                 x=ch[x][1];
174             }else
175                 x=ch[x][0];
176             }
177                 else{
178                     if(!ret) ret=x;
179                     x=ch[x][1];
180                 }
181         }
182         return ret;
183     }
184 }T;
185 
186 int main(){
187     //freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
188     scanf("%d%lf",&n,&s);
189     for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i],&b[i],&rate[i]);     
190     ans=s;double fi=ans/(rate[1]*a[1]+b[1]);
191     T._insert((point){fi,rate[1]*fi});
192     for(int i=2;i<=n;i++){
193         int x=T.getpre_U(-b[i]/a[i]);
194         ans=max(T.key[x].x*b[i]+T.key[x].y*a[i],ans);
195         fi=ans/(rate[i]*a[i]+b[i]);
196         T.maintain_U((point){fi,rate[i]*fi});
197     }
198     printf("%.3lf\n",ans);
199     return 0;
200 }
BZOJ1492

 

PART IV (crazy~) BZOJ 3461

 

3461: Jry的时间表

Time Limit: 60 Sec  Memory Limit: 512 MB
Submit: 14  Solved: 4
[Submit][Status]

Description

 吉丽(JRY)的电脑里有一份时间表,表上有n个时间段,每个时间段吉丽都要和一个妹子约会。每个妹子都有一个属性a_i,表示吉丽和第i个妹子约会至少需要带的money。吉丽特意把a_i标在了第i行,以作备忘。
 你听说了吉丽的这张时间表,决定篡改一下数据,让吉丽花更多的money。当然,你对这n个妹子也有不同的好感度,所以你准备把第i行的数改为b_i。
 有一天你趁机接触到了吉丽的时间表,可是时间紧迫,你最多只能输入两个数据,其他只能通过复制得到了。
 定义“一次操作”为:修改第i行的数据,将a_i改为b_i,选中这个数向上或向下拖动到第j行,这样就使得第min(i,j)至第max(i,j)行的数都被覆盖成了b_i。
 注意:为了提高效率,你不会修改或覆盖同一行两次以上(包括两次)。
 你的时间只够你完成两次操作,你在这么短的时间内仍不忘让吉丽花的money越多越好。请你回答:在最多操作两次的情况下,吉丽最多要花多少money。

 

Input

第一行n。第二行n个数,表示ai。第三行n个数,表示bi。

 

Output

一个数,表示吉丽最多要花的money。

 

Sample Input

7
1 3 4 7 6 1 2
1 1 3 1 5 1 1

Sample Output

31


【其他】
第一次操作:修改第3行,向上拖动到第1行。
第二次操作:修改第5行,向下拖动到第7行。
修改后的数列:3 3 3 7 5 5 5,money和为31,可以验证这是最大值。

【数据范围】
1≤n≤500000,1≤ai,bi≤10^9

HINT

 

数据已加强,By evil佂菡

 

Source

 

复制是两个很有趣的DP。至于两次操作只要翻转一次,两次答案合并就好。

 

来看看我的逗比做法。

 

1)枚举到 i 时,j~i 都变为b[i]的策略。

k<j,j比k优当且仅当:

b[i]×(i-j+1)-(sum[i]-sum[j-1])>b[i]×(i-k+1)-(sum[i]-sum[k-1])

……

(j-k)×b[i]<sum[j-1]-sum[k-1]

(sum[j-1]-sum[k-1])/(j-k)>b[i]

与上题类似的做法,维护上凸壳。

 

2)枚举到 i 时,j~i都变为b[j]的策略。

k<j,j比k优当且仅当:

b[j]×(i-j+1)-(sum[i]-sum[j-1])>b[k]×(i-k+1)-(sum[i]-sum[k-1])

……

(b[j]-b[k])×i>{(j-1)b[j]-sum[j-1]}-{(k-1)b[k]-sum[k-1]}

注意到b[]不递增,没法移项sad~

 

再移过来,(b[j]-b[k])×i-{(j-1)b[j]-sum[j-1]}+{(k-1)b[k]-sum[k-1]}>0

注意到这是ax+b>0的直线形式,很本能地认为,这题是插直线维护凸壳。

这样的凸壳有个显然的性质,凸壳上的直线斜率单调递增,截距递减。

 

插入某条直线L=ax+b,找到相邻的直线使得ai<a<aj。

直线合法仅当L与Li的交点在L与Lj的交点左侧。维护时与插入点维护凸壳类似。

斜率相等的直线直接判截距。

 

于是这道题目我写了两个splay~喜闻乐见。你会发现前面一问也是直线啊!

(事后他们告诉我,这叫动态半平面交!我真弱我连半平面交都不会)

bubuko.com,布布扣
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<algorithm>
  7 #define MAXN 500010
  8 #define INF 10000000000
  9 #define eps 1e-8
 10 using namespace std;
 11 typedef double LD;
 12 typedef long long LL;
 13  
 14 LL a[MAXN],b[MAXN],s[MAXN],f[MAXN],g[MAXN];
 15 int n;
 16 
 17 struct point{
 18     LL x,y;
 19     bool operator<(const point&b)const{
 20         return (x<b.x||x==b.x&&y<b.y);
 21     }
 22     bool operator>(const point&b)const{
 23         return (x>b.x||x==b.x&&y>b.y);
 24     }
 25     point operator-(const point&b)const{
 26         return (point){x-b.x,y-b.y};
 27     }
 28 };
 29 typedef point vector;
 30  
 31 LL cross(vector a,vector b){
 32     return a.x*b.y-b.x*a.y;
 33 }
 34 
 35 //带插入单点的凸壳(动态凸壳?) 
 36 struct Splay_ConvexHull_Point{
 37     point key[MAXN];int pre[MAXN],suc[MAXN];
 38     int ch[MAXN][2],f[MAXN],queue[MAXN],pool[MAXN];
 39     int root,cnt,top;
 40     void clear(){
 41         root=cnt=top=0;
 42     }
 43     int newnode(point v,int fa){
 44         int x=top?pool[top--]:(++cnt);
 45         key[x]=v;f[x]=fa;ch[x][0]=ch[x][1]=0;
 46         return x;
 47     }
 48     void rotate(int x,int t){
 49         int y=f[x];
 50         f[x]=f[y];if(f[y]) ch[f[y]][ch[f[y]][1]==y]=x;
 51         ch[y][t]=ch[x][!t];if(ch[x][!t]) f[ch[x][!t]]=y;
 52         f[ch[x][!t]=y]=x;
 53     }
 54     void splay(int x,int goal){
 55         while(f[x]!=goal){
 56             if(f[f[x]]==goal){
 57                 rotate(x,ch[f[x]][1]==x);
 58             }else{
 59                 int y=f[x],t=(ch[f[y]][1]==y);
 60                 if(ch[y][t]==x) rotate(y,t),rotate(x,t);
 61                 else rotate(x,!t),rotate(x,t);
 62             }
 63         }
 64         if(goal==0) root=x;
 65     }
 66     void erase(int x){
 67         if(!x) return;
 68         int h=0,t=0;
 69         for(queue[t++]=x;h<t;h++){
 70             int v=queue[h];pool[++top]=v;
 71             if(ch[v][0]) queue[t++]=ch[v][0];
 72             if(ch[v][1]) queue[t++]=ch[v][1];
 73         }
 74     }
 75     void maintain(int x){
 76         int p;
 77         if(ch[x][0]){
 78             for(p=ch[x][0];ch[p][1];p=ch[p][1]);
 79             suc[p]=x;pre[x]=p;
 80         }else
 81             pre[x]=0;
 82         if(ch[x][1]){
 83             for(p=ch[x][1];ch[p][0];p=ch[p][0]);
 84             pre[p]=x;suc[x]=p;
 85         }else
 86             suc[x]=0;  
 87     }
 88     int _insert(point v){
 89         if(!root){
 90             root=newnode(v,0);pre[root]=suc[root]=0;
 91             return root;
 92         }
 93         int x=root;
 94         for(;ch[x][key[x]<v];x=ch[x][key[x]<v]);
 95         ch[x][key[x]<v]=newnode(v,x);
 96         x=ch[x][key[x]<v];
 97         splay(x,0);
 98         maintain(x);
 99         return x;
100     }
101     int lower_bound(point v){
102         int x=root,ret=0;point min={INF,INF};
103         while(x){
104             if(!(key[x]<v)) if(key[x]<min) min=key[x],ret=x;
105             x=ch[x][key[x]<v];
106         }
107         return ret;
108     }
109     void maintain_U(point v){
110         int _=lower_bound(v),p,x,y,t;
111         if(_)
112             if(pre[_]){
113                 if(cross(v-key[pre[_]],key[_]-key[pre[_]])>=0) return;
114                 p=_insert(v);
115                  
116                 x=ch[p][1],y=p,t=1;
117                 while(x){
118                     if(suc[x]==0||(cross(key[x]-v,key[suc[x]]-v)<0)){
119                         f[ch[y][t]=x]=y;y=x;t=0;x=ch[x][0];
120                     }else{
121                         pool[++top]=x;erase(ch[x][0]);x=ch[x][1];
122                     }
123                 }
124                 ch[y][t]=0;
125                  
126                 x=ch[p][0],y=p,t=0;
127                 while(x){
128                     if(pre[x]==0||(cross(key[x]-key[pre[x]],v-key[pre[x]])<0)){
129                         f[ch[y][t]=x]=y;y=x;t=1;x=ch[x][1];
130                     }else{
131                         pool[++top]=x;erase(ch[x][1]);x=ch[x][0];
132                     }
133                 }
134                 ch[y][t]=0;
135             }else{
136                 p=_insert(v);x=ch[p][1],y=p,t=1;
137                 while(x){
138                     if(suc[x]==0||(cross(key[x]-v,key[suc[x]]-v)<0)){
139                         f[ch[y][t]=x]=y;y=x;t=0;x=ch[x][0];
140                     }else{
141                         pool[++top]=x;erase(ch[x][0]);x=ch[x][1];
142                     }
143                 }
144                 ch[y][t]=0;
145             }
146         else{
147             p=_insert(v);x=ch[p][0],y=p,t=0;
148             while(x){
149                 if(pre[x]==0||(cross(key[x]-key[pre[x]],v-key[pre[x]])<0)){
150                     f[ch[y][t]=x]=y;y=x;t=1;x=ch[x][1];
151                 }else{
152                     pool[++top]=x;erase(ch[x][1]);x=ch[x][0];
153                 }
154             }
155             ch[y][t]=0;
156         }
157         maintain(p);
158     }
159     int find_U(LD slope){
160         int x=root,ret=0;
161         LD dy=10000000000,dx=0.000000001,ey,ex;
162         while(x){
163             if(pre[x]){
164             ey=key[x].y-key[pre[x]].y;ex=key[x].x-key[pre[x]].x;
165             if(ey-ex*slope>eps){
166                 if(ey*dx-dy*ex<-eps){
167                     ret=x;dy=ey;dx=ex;
168                 }
169                 x=ch[x][1];
170             }else
171                 x=ch[x][0];
172             }
173                 else{
174                     if(!ret) ret=x;
175                     x=ch[x][1];
176                 }
177         }
178         return ret;
179     }
180 }P;
181  
182 struct line{
183     LL a,b;
184     bool operator<(const line&L)const{
185         return (a<L.a);
186     }
187 };
188 LD cross(line L1,line L2){
189     return (LD)(L2.b-L1.b)/(L1.a-L2.a);
190 }
191 
192 //带插入直线的凸壳(动态半平面交?) 
193 struct Splay_ConvexHull_Line{
194     line key[MAXN];int pre[MAXN],suc[MAXN];
195     int ch[MAXN][2],f[MAXN],queue[MAXN],pool[MAXN];
196     int root,cnt,top;
197     void clear(){
198         root=cnt=top=0;
199     }
200     int newnode(line v,int fa){
201         int x=top?pool[top--]:(++cnt);
202         key[x]=v;f[x]=fa;ch[x][0]=ch[x][1]=0;
203         return x;
204     }
205     void rotate(int x,int t){
206         int y=f[x];
207         f[x]=f[y];if(f[y]) ch[f[y]][ch[f[y]][1]==y]=x;
208         ch[y][t]=ch[x][!t];if(ch[x][!t]) f[ch[x][!t]]=y;
209         f[ch[x][!t]=y]=x;
210     }
211     void splay(int x,int goal){
212         while(f[x]!=goal){
213             if(f[f[x]]==goal){
214                 rotate(x,ch[f[x]][1]==x);
215             }else{
216                 int y=f[x],t=(ch[f[y]][1]==y);
217                 if(ch[y][t]==x) rotate(y,t),rotate(x,t);
218                 else rotate(x,!t),rotate(x,t);
219             }
220         }
221         if(goal==0) root=x;
222     }
223     void erase(int x){
224         if(!x) return;
225         int h=0,t=0;
226         for(queue[t++]=x;h<t;h++){
227             int v=queue[h];pool[++top]=v;
228             if(ch[v][0]) queue[t++]=ch[v][0];
229             if(ch[v][1]) queue[t++]=ch[v][1];
230         }
231     }
232     void maintain(int x){
233         int p;
234         if(ch[x][0]){
235             for(p=ch[x][0];ch[p][1];p=ch[p][1]);
236             suc[p]=x;pre[x]=p;
237         }else
238             pre[x]=0;
239         if(ch[x][1]){
240             for(p=ch[x][1];ch[p][0];p=ch[p][0]);
241             pre[p]=x;suc[x]=p;
242         }else
243             suc[x]=0;  
244     }
245     int _insert(line v){
246         if(!root){
247             root=newnode(v,0);pre[root]=suc[root]=0;
248             return root;
249         }
250         int x=root;
251         for(;ch[x][key[x]<v];x=ch[x][key[x]<v]);
252         ch[x][key[x]<v]=newnode(v,x);
253         x=ch[x][key[x]<v];
254         splay(x,0);
255         maintain(x);
256         return x;
257     }
258     int lower_bound(line v){
259         int x=root,ret=0;line min={INF,INF};
260         while(x){
261             if(!(key[x]<v)) if(key[x]<min) min=key[x],ret=x;
262             x=ch[x][key[x]<v];
263         }
264         return ret;
265     }
266     void maintain_D(line v){
267         int _=lower_bound(v),p,x,y,t;
268         if(_)
269             if(v.a==key[_].a){
270                 if(v.b<=key[_].b) return;p=_;key[p].b=v.b;splay(_,0);
271                 x=ch[p][1],y=p,t=1;
272                 while(x){
273                     if(suc[x]==0||cross(v,key[x])-cross(key[x],key[suc[x]])<-eps){
274                         f[ch[y][t]=x]=y;y=x;t=0;x=ch[x][0];
275                     }else{
276                         pool[++top]=x;erase(ch[x][0]);x=ch[x][1];
277                     }
278                 }
279                 ch[y][t]=0;
280                 x=ch[p][0],y=p,t=0;
281                 while(x){
282                     if(pre[x]==0||cross(key[pre[x]],key[x])-cross(key[pre[x]],v)<-eps){
283                         f[ch[y][t]=x]=y;y=x;t=1;x=ch[x][1];
284                     }else{
285                         pool[++top]=x;erase(ch[x][1]);x=ch[x][0];
286                     }
287                 }
288                 ch[y][t]=0;
289                      
290             }else if(pre[_]){
291                 if(cross(key[pre[_]],v)-cross(v,key[_])>-eps) return;
292                 p=_insert(v);
293                 x=ch[p][1],y=p,t=1;
294                 while(x){
295                     if(suc[x]==0||cross(v,key[x])-cross(key[x],key[suc[x]])<-eps){
296                         f[ch[y][t]=x]=y;y=x;t=0;x=ch[x][0];
297                     }else{
298                         pool[++top]=x;erase(ch[x][0]);x=ch[x][1];
299                     }
300                 }
301                 ch[y][t]=0;
302                 x=ch[p][0],y=p,t=0;
303                 while(x){
304                     if(pre[x]==0||cross(key[pre[x]],key[x])-cross(key[pre[x]],v)<-eps){
305                         f[ch[y][t]=x]=y;y=x;t=1;x=ch[x][1];
306                     }else{
307                         pool[++top]=x;erase(ch[x][1]);x=ch[x][0];
308                     }
309                 }
310                 ch[y][t]=0;
311             }else{
312                 p=_insert(v);x=ch[p][1],y=p,t=1;
313                 while(x){
314                     if(suc[x]==0||cross(v,key[x])-cross(key[x],key[suc[x]])<-eps){
315                         f[ch[y][t]=x]=y;y=x;t=0;x=ch[x][0];
316                     }else{
317                         pool[++top]=x;erase(ch[x][0]);x=ch[x][1];
318                     }
319                 }
320                 ch[y][t]=0;
321             }
322         else{
323             p=_insert(v);x=ch[p][0],y=p,t=0;
324             while(x){
325                 if(pre[x]==0||cross(key[pre[x]],key[x])-cross(key[pre[x]],v)<-eps){
326                     f[ch[y][t]=x]=y;y=x;t=1;x=ch[x][1];
327                 }else{
328                     pool[++top]=x;erase(ch[x][1]);x=ch[x][0];
329                 }
330             }
331             ch[y][t]=0;
332         }
333         maintain(p);
334     }
335     LL find_D(LL X){
336         int x=root,ret=0;LD X1,X2;
337         while(x){
338             if(pre[x]+suc[x]==0)
339                  return key[x].a*X+key[x].b;
340             else if(pre[x]==0){
341                 X2=cross(key[x],key[suc[x]]);
342                 if(X2-X>-eps) return key[x].a*X+key[x].b;
343                 else x=ch[x][1];
344             }else if(suc[x]==0){
345                 X1=cross(key[pre[x]],key[x]);
346                 if(X1-X<eps) return key[x].a*X+key[x].b;
347                 else x=ch[x][0];
348             }else{
349                 X1=cross(key[pre[x]],key[x]);
350                 X2=cross(key[x],key[suc[x]]);
351                 if(X1-X<eps&&X2-X>-eps) return key[x].a*X+key[x].b;
352                 if(X1-X>eps) x=ch[x][0]; else x=ch[x][1];
353             }
354         }
355     }
356 }L;
357  
358 void work(){
359     int j;P.clear();L.clear();
360     for(int i=1;i<=n;i++){
361         P.maintain_U((point){i,s[i-1]});
362         j=P.find_U(b[i]);
363         f[i]=max(b[i]*(i-P.key[j].x+1)+P.key[j].y-s[i],f[i]);
364         L.maintain_D((line){b[i],1ll*b[i]*(-(i-1))+s[i-1]});
365         f[i]=max(L.find_D(i)-s[i],f[i]);
366     }
367     for(int i=2;i<=n;i++) f[i]=max(f[i],f[i-1]);
368 }
369 
370 char buf[10000000],*pt = buf,*o = buf;
371 int getint(){
372     int f = 1,x = 0;
373     while((*pt != -) && (*pt < 0 || *pt > 9))    pt ++;
374     if(*pt == -)    f = -1,pt ++;    else    x = *pt++ - 48;
375     while(*pt >= 0 && *pt <= 9)    x = x * 10 + *pt ++ - 48;
376     return x * f;
377 }
378 
379 int main(){
380     //freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
381     fread(buf,1,10000000,stdin);
382     n=getint();
383     for(int i=1;i<=n;i++) a[i]=getint();
384     for(int i=1;i<=n;i++) b[i]=getint();
385     for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
386     work();
387     for(int i=1;i<=n;i++) g[i]=f[i];
388     reverse(g+1,g+n+1);
389     reverse(a+1,a+n+1);reverse(b+1,b+n+1);
390     for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
391     memset(f,0,sizeof(f));
392     work();
393     LL ans=0;
394     for(int i=0;i<=n;i++) ans=max(f[i]+g[i+1],ans);
395     printf("%lld\n",s[n]+ans);
396     return 0;
397 }
BZOJ3461

 

有趣的凸壳问题~,布布扣,bubuko.com

有趣的凸壳问题~

标签:des   style   blog   http   color   os   io   strong   

原文地址:http://www.cnblogs.com/fullpower/p/3904903.html

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!