【ContestHunter】【弱省胡策】【Round8】

平衡树维护凸壳/三角函数+递推+线段树


  官方题解:http://pan.baidu.com/s/1sjQbY8H

洛阳城里春光好

  题目大意:(其实出题人已经写的很简短了……直接copy的-_-。sorry!)

一个平面上的n个点构成一个点集。老师会进行Q次操作,每次操作有以下两种可能:
1. 插入操作:给定两个实数x,y,向点集中加入一个坐标为(x,y)的点。
2. 查询操作:给定实数k,取点集中任一点(x,y),求满足方程y=kx+b的b的最大值。
现在小Z想知道,对于数学老师的每次查询,符合题意的b值是多少。

  容易发现我们要找的点是在 凸包上 上凸壳上!(一开始总在想凸包……我真是naive

  然后凸包上的线段的斜率满足单调性,所以我们在凸包上二分(lower_bound)即可找到所求的点……

  这题我是用两个map来实现的,一个map存凸包,另一个map存斜率。

  这里我处理斜率的时候少考虑了一个地方:我在插入凸包中插入一个新点时(p[x]=y),是删除它左右两个点对应直线的斜率,再加入两个新的斜率,然后对凸包进行调整。然而如果p[x]这个位置原来就有一个点的话!就应该是删掉原来的点与两边的点之间线段的斜率,再加入新的斜率,然后对凸包进行调整。

  比较开心的是get了一份平衡树维护凸包的模板~(来自这里:http://blog.csdn.net/auto_ac/article/details/10664641

  其实这个是上凸壳的……如果是凸包的话我们维护两个凸壳就好了,下凸壳的维护方法:将所有点的y坐标取反,然后维护一个新的“上凸壳”(对应原图的下凸壳)这两个凸壳只有第一个点和最后一个点会是相同的。

 

  另外,这题用KD-Tree应该也可做。。。判一下四个角就可以了= =(思维难度和代码难度好像要更优一点,额……不过用map的话代码难度也没有很高

  我写KDTree的Insert的时候没有把插进来的这个点赋值

  1 //Round8 A
  2 #include<vector>
  3 #include<map>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define rep(i,n) for(int i=0;i<n;++i)
 10 #define F(i,j,n) for(int i=j;i<=n;++i)
 11 #define D(i,j,n) for(int i=j;i>=n;--i)
 12 using namespace std;
 13 typedef long long LL;
 14 inline int getint(){
 15     int r=1,v=0; char ch=getchar();
 16     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
 17     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
 18     return r*v;
 19 }
 20 const int N=1e5+10;
 21 /*******************template********************/
 22 //#define debug
 23 
 24 int n,m;
 25 double ans=1;
 26 typedef map<double,double> mii;
 27 typedef map<double,double>::iterator iter;
 28 #define X first
 29 #define Y second
 30 double cross(iter o,iter a,iter b){
 31     return (a->X - o->X) * (b->Y - o->Y) -
 32            (a->Y - o->Y) * (b->X - o->X);
 33 }
 34 mii up,slop;
 35 
 36 inline double slope(iter a,iter b){
 37     return (b->Y - a->Y)/(b->X - a->X);
 38 }
 39 bool inside(mii &p,double x,double y){
 40     if (!p.size()) return 0;
 41     if (x<p.begin()->X || x>p.rbegin()->X) return 0;
 42     if (p.count(x)) return y<=p[x];
 43     p[x]=y;
 44     iter cur = p.lower_bound(x),i,j;
 45     i=j=cur; i--; j++;
 46     bool ret=cross(i,cur,j)>=0;
 47     p.erase(cur);
 48     return ret;
 49 }
 50 void add(mii &p,double x,double y){
 51     if (inside(p,x,y)) return;
 52     if (p.count(x)){
 53         iter cur=p.lower_bound(x),i=cur,j=cur;
 54         i--;j++;
 55         if (cur!=p.begin()) slop.erase(slope(i,cur));
 56         if (j!=p.end()) slop.erase(slope(cur,j));
 57     }
 58     p[x]=y;
 59     iter cur=p.lower_bound(x),i=cur,j=cur;
 60     i--; j++;
 61     if (cur!=p.begin() && j!=p.end()) slop.erase(slope(i,j));
 62     if (cur!=p.begin()) slop[slope(i,cur)]=cur->X;
 63     if (j!=p.end()) slop[slope(cur,j)]=j->X;
 64     for(i=cur,i--,j=i,j--;i!=p.begin() && cur!=p.begin();i=j--)
 65         if (cross(j,i,cur)>=0){
 66             slop.erase(slope(j,i));
 67             slop.erase(slope(i,cur));
 68             slop[slope(j,cur)]=cur->X;
 69             p.erase(i);
 70         }
 71         else break;
 72     for(i=cur,i++,j=i,j++;i!=p.end() && j!=p.end();i=j++)
 73         if (cross(cur,i,j)>=0){
 74             slop.erase(slope(cur,i));
 75             slop.erase(slope(i,j));
 76             slop[slope(cur,j)]=j->X;
 77             p.erase(i);
 78         }
 79         else break;
 80 }
 81 double query(double k){
 82     double x,y;
 83     iter it=slop.lower_bound(k);
 84     if (it==slop.end()) x=up.begin()->X,y=up.begin()->Y;
 85     else x=it->Y,y=up[x];
 86 //    printf("query k=%f tmpk=%f x=%f y=%f\n",k,it->X,x,y);
 87     return y-k*x;
 88 }
 89 
 90 int main(){
 91 #ifndef ONLINE_JUDGE
 92     freopen("A.in","r",stdin);
 93     freopen("A.out","w",stdout);
 94 #endif 
 95     int type=getint();
 96     double x,y,k;
 97     n=getint(); m=getint();
 98     F(i,1,n){
 99         scanf("%lf%lf",&x,&y);
100         add(up,x,y);
101 #ifdef debug
102 //    for(iter it=up.begin();it!=up.end();it++)
103 //        printf("%f %f\n",it->X,it->Y);
104 //    puts("");
105 #endif
106     }
107 #ifdef debug
108     puts("up tu ke:");
109     for(iter it=up.begin();it!=up.end();it++)
110         printf("%f %f\n",it->X,it->Y);
111     puts("");
112     puts("xie lv & x :");
113     for(iter it=slop.begin();it!=slop.end();it++)
114         printf("%f %f\n",it->X,it->Y);
115     puts("");
116 #endif
117     char cmd[10];
118     double ans=1;
119     F(i,1,m){
120         scanf("%s",cmd);
121         if (cmd[0]=='i'){
122             scanf("%lf%lf",&x,&y);
123             if (type==2) x=x/ans,y=y/ans;
124             add(up,x,y);
125         }else{
126             scanf("%lf",&k);
127             if (type==2) k=k/ans;
128             printf("%.3f\n",ans=query(k));
129         }
130     }
131     return 0;
132 }
View Code(map维护凸包)
  1 //Round8 A
  2 #include<vector>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<iostream>
  7 #include<algorithm>
  8 #define rep(i,n) for(int i=0;i<n;++i)
  9 #define F(i,j,n) for(int i=j;i<=n;++i)
 10 #define D(i,j,n) for(int i=j;i>=n;--i)
 11 using namespace std;
 12 typedef long long LL;
 13 inline int getint(){
 14     int r=1,v=0; char ch=getchar();
 15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
 16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
 17     return r*v;
 18 }
 19 const int N=2e5+10;
 20 const double INF=1e30;
 21 /*******************template********************/
 22 
 23 int n,m,D,p[N<<1],cnt,tot,root;
 24 struct node{
 25     double d[2],mx[2],mn[2];
 26     int l,r,D,size;
 27     double& operator [] (int x){return d[x];}
 28 }t[N<<2],now;
 29 bool cmp(int x,int y){return t[x][D]<t[y][D];}
 30 
 31 #define L t[o].l
 32 #define R t[o].r
 33 #define mid (l+r>>1)
 34 inline void Push_up(int o){
 35     F(i,0,1){
 36         t[o].mn[i]=min(t[o][i],min(t[L].mn[i],t[R].mn[i]));
 37         t[o].mx[i]=max(t[o][i],max(t[L].mx[i],t[R].mx[i]));
 38     }
 39     t[o].size=t[L].size+t[R].size+1;
 40 }
 41 inline int build(int l,int r,int dir){
 42     D=dir;
 43     nth_element(p+l,p+mid,p+r+1,cmp);
 44     int o=p[mid];
 45     t[o].D=dir;
 46     L=l<mid ? build(l,mid-1,dir^1) : 0;
 47     R=mid<r ? build(mid+1,r,dir^1) : 0;
 48     Push_up(o);
 49     return o;
 50 }
 51 inline void dfs(int o){
 52     if (!o) return;
 53     dfs(L); p[++cnt]=o; dfs(R);
 54 }
 55 inline void rebuild(int &o){
 56     cnt=0; dfs(o);
 57     o=build(1,cnt,t[o].D);
 58 }
 59 inline void Insert(int &o,int dir){
 60     if (!o){
 61         o=++n;
 62         F(i,0,1) t[o].mn[i]=t[o].mx[i]=t[o][i]=now[i];
 63         t[o].D=dir; t[o].size=1;
 64         return;
 65     }
 66     if (now[dir]<t[o][dir]){
 67         Insert(L,dir^1); Push_up(o);
 68         if (t[L].size>t[o].size*0.7) rebuild(o);
 69     }else{
 70         Insert(R,dir^1); Push_up(o);
 71         if (t[R].size>t[o].size*0.7) rebuild(o);
 72     }
 73 }
 74 
 75 double ans=1;
 76 inline double getans(int o,double k){
 77     if (!o) return -INF;
 78     return t[o][1]-k*t[o][0];
 79 }
 80 inline double calc(int o,double k){
 81     if (!o) return -INF;
 82     double ans=max(t[o].mn[1]-k*t[o].mn[0],t[o].mn[1]-k*t[o].mx[0]);
 83     ans=max(ans,max(t[o].mx[1]-k*t[o].mn[0],t[o].mx[1]-k*t[o].mx[0]));
 84     return ans;
 85 }
 86 inline void query(int o,double k){
 87     if (!o) return;
 88     double dl=calc(L,k),dr=calc(R,k),d0=getans(o,k);
 89     ans=max(ans,d0);
 90     if (dl<dr){
 91         if (dr>ans && R) query(R,k);
 92         if (dl>ans && L) query(L,k);
 93     }else{
 94         if (dl>ans && L) query(L,k);
 95         if (dr>ans && R) query(R,k);
 96     }
 97 }
 98 
 99 int main(){
100 #ifndef ONLINE_JUDGE
101     freopen("A.in","r",stdin);
102     freopen("A.out","w",stdout);
103 #endif 
104     F(i,0,1) t[i].mn[i]=INF,t[i].mx[i]=-INF;
105     t[0].size=0;
106 
107     int type=getint();
108     tot=n=getint(); m=getint();
109     F(i,1,n) scanf("%lf%lf",&t[i][0],&t[i][1]),p[i]=i;
110     root=build(1,n,0);
111 
112     char cmd[10]; double k;
113     F(i,1,m){
114         scanf("%s",cmd);
115         if (cmd[0]=='i'){
116             scanf("%lf%lf",&now[0],&now[1]);
117             if (type==2) now[0]/=ans,now[1]/=ans;
118             Insert(root,0);
119         }else{
120             scanf("%lf",&k);
121             if (type==2) k/=ans;
122             ans=-INF;
123             query(root,k);
124             printf("%.3f\n",ans);
125         }
126     }
127     return 0;
128 }
View Code(KDTree)

 

序列

  一道很棒的题目,具体过程戳官方题解吧……

  一个神奇的转化是对每一项都乘了一个$2sin(\frac{k}{2})$,然后利用积化和差公式,将一个$\sum$求和转化成了一个可以裂项相消,$O(1)$计算的式子……

  然后就可以离散化用线段树维护了,感觉细节处理蛮厉害的。。。蒟蒻除了模板部分都只能抄标程

  因为搞出来sin和cos以后就可以打tag了……且标记支持合并= =

  1 //Round8 C
  2 #include<vector>
  3 #include<cmath>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define rep(i,n) for(int i=0;i<n;++i)
 10 #define F(i,j,n) for(int i=j;i<=n;++i)
 11 #define D(i,j,n) for(int i=j;i>=n;--i)
 12 using namespace std;
 13 typedef long long LL;
 14 inline int getint(){
 15     int r=1,v=0; char ch=getchar();
 16     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
 17     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
 18     return r*v;
 19 }
 20 const int N=150010;
 21 /*******************template********************/
 22 
 23 int n,m,num,k,c[N<<1];
 24 double sink;
 25 
 26 struct ques{
 27     int l,r,d;
 28 }q[N];
 29 
 30 struct node{
 31     double si,co;
 32     int tag;
 33 }t[N<<2];
 34 #define L (o<<1)
 35 #define R (o<<1|1)
 36 #define mid (l+r>>1)
 37 #define lch L,l,mid
 38 #define rch R,mid+1,r
 39 
 40 void maintain(int o){
 41     t[o].si=t[L].si+t[R].si;
 42     t[o].co=t[L].co+t[R].co;
 43 }
 44 void change(int o,int d){
 45     t[o].tag+=d;
 46     double si1=t[o].si,si2=sin(d),co1=t[o].co,co2=cos(d);
 47     t[o].si=si1*co2+co1*si2;
 48     t[o].co=co1*co2-si1*si2;
 49 }
 50 void Push_down(int o){
 51     if (t[o].tag){
 52         change(L,t[o].tag);
 53         change(R,t[o].tag);
 54         t[o].tag=0;
 55     }
 56 }
 57 void build(int o,int l,int r){
 58     if (l==r){
 59         t[o].si=(cos(k*c[l]-k*0.5)-cos(k*(c[l+1]-1)+k*0.5))/(2*sink);
 60         t[o].co=(sin(k*(c[l+1]-1)+k*0.5)-sin(k*c[l]-k*0.5))/(2*sink);
 61     }else{
 62         build(lch); build(rch);
 63         maintain(o);
 64     }
 65 }
 66 void update(int o,int l,int r,int ql,int qr,int v){
 67     if (ql<=l && qr>=r) change(o,v);
 68     else{
 69         Push_down(o);
 70         if (ql<=mid) update(lch,ql,qr,v);
 71         if (qr>mid) update(rch,ql,qr,v);
 72         maintain(o);
 73     }
 74 }
 75 double query(int o,int l,int r,int ql,int qr){
 76     if (ql<=l && qr>=r) return t[o].si;
 77     else{
 78         Push_down(o);
 79         double ans=0;
 80         if (ql<=mid) ans+=query(lch,ql,qr);
 81         if (qr>mid) ans+=query(rch,ql,qr);
 82         return ans;
 83     }
 84 }
 85 
 86 int main(){
 87 #ifndef ONLINE_JUDGE
 88     freopen("C.in","r",stdin);
 89     freopen("C.out","w",stdout);
 90 #endif 
 91     n=getint(); m=getint(); k=getint();
 92     sink=sin(double(k)/2.0);
 93     int tot=0;
 94     c[++tot]=0; c[++tot]=n+1;
 95     F(i,1,m){
 96         q[i].l=getint(),q[i].r=getint(),q[i].d=getint();
 97         c[++tot]=q[i].l; c[++tot]=q[i].r+1;
 98     }
 99     sort(c+1,c+tot+1);
100     num=unique(c+1,c+tot+1)-c-1;
101     num--; build(1,1,num);
102     F(i,1,m){
103         int d=q[i].d,l,r;
104         l=lower_bound(c+1,c+num+1,q[i].l)-c;
105         r=lower_bound(c+1,c+num+1,q[i].r+1)-c-1;
106         if (d) update(1,1,num,l,r,d);
107         else printf("%.10f\n",query(1,1,num,l,r));
108     }
109     return 0;
110 }
View Code

 

posted @ 2015-06-23 18:48  Tunix  阅读(...)  评论(...编辑  收藏