zoukankan      html  css  js  c++  java
  • BZOJ_4311_向量_线段树按时间分治

    BZOJ_4311_向量_CDQ分治+线段树按时间分治

    Description

    你要维护一个向量集合,支持以下操作:
    1.插入一个向量(x,y)
    2.删除插入的第i个向量
    3.查询当前集合与(x,y)点积的最大值是多少。如果当前是空集输出0

    Input

    第一行输入一个整数n,表示操作个数
    接下来n行,每行先是一个整数t表示类型,如果t=1,输入向量
    (x,y);如果t=2,输入id表示删除第id个向量;否则输入(x,y),查询
    与向量(x,y)点积最大值是多少。
    保证一个向量只会被删除一次,不会删没有插入过的向量

    Output

    对于每条t=3的询问,输出一个答案

    Sample Input

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

    Sample Output

    18
    15

    HINT

    n<=200000 1<=x,y<=10^6

    Ans=x1*x+y1*y。
    y1=-x/y *x1+Ans/y。
    因为y是正数,也就是说我们只需要y轴正无穷的地方能看到的点。
    于是维护上凸壳即可。
    但是不会删除,考虑线段树按时间分治,对log个节点上用vector插入这个点。
    然后[l,r]这段的询问向上找,在线段树的结点上用vector里的点更新答案。
    可以预先把插入的点按横坐标排序,这样求凸壳就是O(n)的了。
    并且询问也可以向上归并,时间复杂度O(nlogn)。
     
    代码:
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    inline char nc() {
        static char buf[100000],*p1,*p2;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    int rd() {
        int x=0; char s=nc();
        while(s<'0'||s>'9') s=nc();
        while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
        return x;
    }
    typedef long long ll;
    typedef double f2;
    #define ls p<<1
    #define rs p<<1|1
    #define N 200050
    struct Point {
        ll x,y;
        Point() {}
        Point(ll x_,ll y_) :
            x(x_),y(y_) {}
    };
    struct A {
        Point p;
        int bg,ed;
        bool operator < (const A &u) const {
            return p.x<u.p.x;
        }
    }P[N];
    f2 Slp(const Point &p1,const Point &p2) {
        if(p1.x==p2.x) return p2.y>p1.y?1e18:-1e18;
        return 1.0*(p2.y-p1.y)/(p2.x-p1.x);
    }
    ll f[N];
    f2 qk[N];
    ll qx[N],qy[N];
    vector<Point>V[N<<2];
    int n,m,id,t[N],tmp[N];
    Point S[N];
    void update(int l,int r,int x,int y,int p,Point pp) {
        if(x<=l&&y>=r) {
            V[p].push_back(pp); return ;
        }
        int mid=(l+r)>>1;
        if(x<=mid) update(l,mid,x,y,ls,pp);
        if(y>mid) update(mid+1,r,x,y,rs,pp);
    }
    Point pp;
    void solve(int l,int r,int p) {
        int i,lim;
        if(l==r) {
            lim=V[p].size();
            for(i=0;i<lim;i++) {
                pp=V[p][i];
                f[l]=max(f[l],pp.x*qx[l]+pp.y*qy[l]);
            }
            return ;
        }
        int mid=(l+r)>>1;
        solve(l,mid,ls); solve(mid+1,r,rs);
        int j=l,k=mid+1; i=l;
        while(j<=mid&&k<=r) {
            if(qk[t[j]]>=qk[t[k]]) tmp[i++]=t[j++];
            else tmp[i++]=t[k++];
        }
        while(j<=mid) tmp[i++]=t[j++];
        while(k<=r) tmp[i++]=t[k++];
        for(i=l;i<=r;i++) t[i]=tmp[i];
        lim=V[p].size();
        if(lim==0) return ;
        int top=0;
        for(i=0;i<lim;i++) {
            pp=V[p][i];
            while(top>1&&Slp(S[top-1],S[top])<=Slp(S[top-1],pp)) top--;
            S[++top]=pp;
        }
        j=1;
        for(i=l;i<=r;i++) {
            while(j<top&&Slp(S[j],S[j+1])>=qk[t[i]]) j++;
            f[t[i]]=max(f[t[i]],qx[t[i]]*S[j].x+qy[t[i]]*S[j].y);
        }
    }
    int main() {
        // freopen("tt.in","r",stdin);
        // freopen("tt.out","w",stdout);
        n=rd();
        int opt,i,x,y;
        for(i=1;i<=n;i++) {
            opt=rd();
            if(opt==1) {
                x=rd(); y=rd();
                P[++id].p=Point(x,y);
                P[id].bg=m+1;
            }else if(opt==2) {
                x=rd();
                P[x].ed=m;
                if(!m) P[x].ed=-1;
            }else {
                m++; x=rd(); y=rd();
                qk[m]=(-1.0*x/y);
                qx[m]=x; qy[m]=y;
            }
        }
        sort(P+1,P+id+1);
        for(i=1;i<=id;i++) {
            if(P[i].bg<=m&&P[i].ed!=-1) {
                P[i].ed=P[i].ed?P[i].ed:m;
                update(1,m,P[i].bg,P[i].ed,1,P[i].p);
            }
            // printf("%d %d
    ",P[i].bg,P[i].ed);
        }
        for(i=1;i<=m;i++) t[i]=i;
        solve(1,m,1);
        for(i=1;i<=m;i++) printf("%lld
    ",f[i]);
    }
    
  • 相关阅读:
    正则表达式获取字符串中html<input>标签指定value值
    [转]利用SqlBulkCopy快速大批量导入数据(SqlBulkCopy强大)
    ASP.NET数据库操作常用类
    response.redirect 和Server.Transfer有什么区别?
    数据驱动的依存句法分析方法简介(一)
    C#序列化问题
    MSSQL 标量函数
    事件和委托问题转
    Copy指定目录下的所有文件到新位置
    页面指定播放视频
  • 原文地址:https://www.cnblogs.com/suika/p/9237377.html
Copyright © 2011-2022 走看看