zoukankan      html  css  js  c++  java
  • 【BZOJ3533】向量集(SDOI2014)-线段树+凸壳+二分

    测试地址:向量集
    做法:本题需要用到线段树+凸包+二分。
    首先恭喜一下自己达成BZOJ200AC……(突然想起,这不会有多少人看得见)
    令询问的向量为(a,b),序列中第i个向量为(xi,yi),那么要求lir时,axi+byi的最大值,令这个式子为k,则有:
    yi=abxi+kb
    注意到b=0时只需要算xi的最大值就行了,所以我们不考虑ab没有意义的问题。
    b>0时,这相当于在所有点(xi,yi)上作斜率为ab的直线,求最大的截距,显然可以维护一个上凸壳,然后在上凸壳上二分解决。
    b<0时,直接将所有xi,yi变成它们的相反数,这样就又转化为了求最大截距的问题,用上面的方法做就行了。
    然而这只是一次询问的情况,要支持多次区间询问,我们就要用线段树维护一个区间内点的上凸壳。那插入操作怎么办?我们可以一开始先开好线段树的空间,但是只有当一个区间内的点被插入完整时,才计算这个区间的凸壳。显然可知,处理凸壳的总时间是O(nlogn),一次询问的时间是O(log2n),可以通过此题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=400010;
    const ll inf=1000000000ll*1000000000ll;
    int n,tot=0,pos[N];
    char s,op[3];
    struct point
    {
        ll x,y;
        point operator + (point a) const
        {
            point s={x+a.x,y+a.y};
            return s;
        }
        point operator - (point a) const
        {
            point s={x-a.x,y-a.y};
            return s;
        }
        ll operator * (point a) const
        {
            return x*a.y-y*a.x;
        }
    };
    
    ll dot(point a,point b)
    {
        return a.x*b.x+a.y*b.y;
    }
    
    struct convex
    {
        int n;
        point *a;
    
        void init(int now)
        {
            n=0;
            a=new point [now+5];
        }
    
        void push(point s)
        {
            while(n>1&&(s-a[n])*(a[n]-a[n-1])<=0) n--;
            a[++n]=s;
        }
    
        void merge(convex &lc,convex &rc)
        {
            init(lc.n+rc.n);
    
            int l=1,r=1;
            while(l<=lc.n&&r<=rc.n)
            {
                int lx=lc.a[l].x,rx=rc.a[r].x;
                if (lx<rx||(lx==rx&&lc.a[l].y<rc.a[r].y)) push(lc.a[l]),l++;
                else push(rc.a[r]),r++;
            }
            if (l>lc.n)
            {
                while(r<=rc.n)
                    push(rc.a[r]),r++;
            }
            else
            {
                while(l<=lc.n)
                    push(lc.a[l]),l++;
            }
        }
    
        ll find(ll x,ll y)
        {
            point s={x,y};
            if (y<0) s.x=-x,s.y=-y;
            int l=1,r=n;
            while(l<r)
            {
                int mid=(l+r)>>1;
                if (dot(a[mid],s)<=dot(a[mid+1],s)) l=mid+1;
                else r=mid;
            }
            return dot(s,a[l]);
        }
    };
    
    struct Seg
    {
        convex a[2];
    }seg[N<<2];
    
    ll decode(ll x,ll lastans)
    {
        return x^(lastans&0x7fffffff);
    }
    
    void buildtree(int no,int l,int r)
    {
        if (l==r) {pos[l]=no;return;}
        int mid=(l+r)>>1;
        buildtree(no<<1,l,mid);
        buildtree(no<<1|1,mid+1,r);
    }
    
    void add(int id,ll x,ll y)
    {
        int now=pos[id];
        point nxt={x,y};
        seg[now].a[0].init(1);seg[now].a[0].push(nxt);
        nxt.x=-x,nxt.y=-y;
        seg[now].a[1].init(1);seg[now].a[1].push(nxt);
        while((now&1)&&now>1)
        {
            now>>=1;
            seg[now].a[0].merge(seg[now<<1].a[0],seg[now<<1|1].a[0]);
            seg[now].a[1].merge(seg[now<<1].a[1],seg[now<<1|1].a[1]);
        }
    }
    
    ll query(int no,int l,int r,int s,int t,ll x,ll y)
    {
        if (l>=s&&r<=t) return seg[no].a[y<0].find(x,y);
        ll ans=-inf;
        int mid=(l+r)>>1;
        if (s<=mid) ans=max(ans,query(no<<1,l,mid,s,t,x,y));
        if (t>mid) ans=max(ans,query(no<<1|1,mid+1,r,s,t,x,y));
        return ans;
    }
    
    int main()
    {
        scanf("%d %c",&n,&s);
    
        ll lastans=0;
        buildtree(1,1,n);
        for(int i=1;i<=n;i++)
        {
            ll x,y;
            int l,r;
            scanf("%s",op);
            if (op[0]=='A')
            {
                scanf("%lld%lld",&x,&y);
                if (s!='E') x=decode(x,lastans),y=decode(y,lastans);
                add(++tot,x,y);
            }
            else
            {
                scanf("%lld%lld%d%d",&x,&y,&l,&r);
                if (s!='E')
                {
                    x=decode(x,lastans),y=decode(y,lastans);
                    l=decode(l,lastans),r=decode(r,lastans);
                }
                printf("%lld
    ",lastans=query(1,1,n,l,r,x,y));
            }
        }
    
        return 0;
    }
  • 相关阅读:
    设计模式 学习笔记(8) 适配器模式、单例模式、享元模式
    设计模式 学习笔记(7) 抽象工厂模式、状态模式
    判断页面是否被嵌入iframe里面
    css3的transform:tanslateZ没有效果
    vuecli3多页应用配置与优化
    正则的test和exec方法与字符串的search,replace,match,split方法的使用
    实验 1:Mininet 源码安装和可视化拓扑工具
    2020软件工程第一次作业
    R12新功能
    FSG(1) FSG报表组件
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793368.html
Copyright © 2011-2022 走看看