zoukankan      html  css  js  c++  java
  • 【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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",query(1,1,num,l,r));
    108     }
    109     return 0;
    110 }
    View Code
  • 相关阅读:
    synchronized一个(二)
    org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
    java.lang.AbstractMethodError: org.mybatis.spring.transaction.SpringManagedTransaction.getTimeout
    NTFS簇大小对硬盘性能的影响测试
    Win10 开机自动打开上次未关闭程序怎么办
    Win10快速访问怎么关闭?
    激活windows 10 LTSC 2019(无需工具)
    WPS文字双行合一
    插入百度地图代码后,页面文字不能被选中的解决方案
    WPS文字批量选中整行(以第?章为例)
  • 原文地址:https://www.cnblogs.com/Tunix/p/4596109.html
Copyright © 2011-2022 走看看