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]);
    }
    
  • 相关阅读:
    Windows server 2016 解决“无法完成域加入,原因是试图加入的域的SID与本计算机的SID相同。”
    Windows Server 2016 辅助域控制器搭建
    Windows Server 2016 主域控制器搭建
    Net Framework 4.7.2 覆盖 Net Framework 4.5 解决办法
    SQL SERVER 2012更改默认的端口号为1772
    Windows下彻底卸载删除SQL Serever2012
    在Windows Server2016中安装SQL Server2016
    SQL Server 创建索引
    C#控制台或应用程序中两个多个Main()方法的设置
    Icon cache rebuilding with Delphi(Delphi 清除Windows 图标缓存源代码)
  • 原文地址:https://www.cnblogs.com/suika/p/9237377.html
Copyright © 2011-2022 走看看