• bzoj 3533: [Sdoi2014]向量集 线段树维护凸包


    题目大意:

    http://www.lydsy.com/JudgeOnline/problem.php?id=3533

    题解:

    首先我们把这些向量都平移到原点.这样我们就发现:
    对于每次询问所得到的ans一定由凸包上的点做出贡献。
    我们按照给出的询问点的纵坐标的正负做出划分:
    若为正:那么对答案做出贡献的点一定在上凸壳上
    若为负:那么对答案做出贡献的点一定在下凸壳上
    所以我们可以分别考虑上下凸壳.不失一般性,我们假设纵坐标为正.
    那么这时候答案肯定在上凸壳上
    并且这个上凸壳上的所有点和询问点组成的答案一定是一个单峰函数
    所以我们三分解决这个问题
    那么现在的问题就是解决查询的是一个区间的问题了
    首先我们发现,对于不同的区间的查询结果,合并时只需要去max即可
    所以我们可以把询问的区间拆成若干个区间合并得到结果
    所以我们用线段树维护即可.
    但是合并凸包的复杂度是(O(n)),我们不可能每次插入一个点都更新
    但是我们发现,对于每个区间,只有里面所有的点都被插入后才可能会被查询到
    所以我们只在一个区间内所有的点都被插入后再合并左右子树的凸包即可.
    复杂度?
    每个点只会被合并(logn)次,每次查询是(log^2n)
    所以总复杂度是(O(mlog^2n))

    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    template<typename T>inline void read(T &x){
        x=0;char ch;bool flag = false;
        while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
        while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    inline ll cat_max(const ll &a,const ll &b){return a>b ? a:b;}
    inline ll cat_min(const ll &a,const ll &b){return a<b ? a:b;}
    const ll maxn = 400010;
    struct Point{
        ll x,y;
        Point(const ll &a=0,const ll &b=0){x=a;y=b;}
        bool friend operator < (const Point &a,const Point &b){
            return a.x == b.x ? a.y < b.y : a.x < b.x;
        }
        void print(){
            printf("Point : (%lld,%lld)
    ",x,y);
        }
    };
    Point operator - (const Point &a,const Point &b){
        return Point(a.x-b.x,a.y-b.y);
    }
    ll operator * (const Point &a,const Point &b){
        return a.x*b.x + a.y*b.y;
    }
    ll cross(const Point &a,const Point &b){
        return a.x*b.y - a.y*b.x;
    }
    struct SB{
        int cmd,l,r,id;
        Point p;
    }op[maxn];
    int nowpos;
    inline void Unionu(const vector<Point> &a,const vector<Point> &b,vector<Point> &c){
        c.clear();int m = 0,siza = a.size(),sizb = b.size(),i=0,j=0;
        Point p;
        while(i < siza || j < sizb){
            if((i == siza) || ((j < sizb) && (b[j] < a[i]))) p = b[j++];
            else p = a[i++];
            while(m > 1 && cross(c[m-1] - c[m-2],p - c[m-1]) >= 0) -- m,c.pop_back();
            m++;c.push_back(p);
        }
    }
    inline void Uniond(const vector<Point> &a,const vector<Point> &b,vector<Point> &c){
        c.clear();int m = 0,siza = a.size(),sizb = b.size(),i=0,j=0;
        Point p;
        while(i < siza || j < sizb){
            if((i == siza) || ((j < sizb) && (b[j] < a[i]))) p = b[j++];
            else p = a[i++];
            while(m > 1 && cross(c[m-1] - c[m-2],p - c[m-1]) <= 0) -- m,c.pop_back();
            m++;c.push_back(p);
        }
    }
    struct Node{
        vector<Point>Tu,Td;
        Node *ch[2];
    }*null,*root;
    inline void init(){
        null = new Node();null->ch[0] = null->ch[1] = null;
        null->Tu.clear();null->Td.clear();root = null;    
    }
    inline Node* newNode(){
        Node *p = new Node();p->ch[0] = p->ch[1] = null;
        p->Tu.clear();p->Td.clear();return p;
    }
    void insert(Node* &p,int l,int r){
        if(p == null) p = newNode();
        if(l == r){
            p->Tu.clear();p->Td.clear();
            p->Tu.push_back(op[nowpos].p);
            p->Td.push_back(op[nowpos].p);
            return;
        }
        int mid = (l+r) >> 1;
        if(op[nowpos].id <= mid) insert(p->ch[0],l,mid);
        else insert(p->ch[1],mid+1,r);
        if(op[nowpos].id == r){
            Unionu(p->ch[0]->Tu,p->ch[1]->Tu,p->Tu);
            Uniond(p->ch[0]->Td,p->ch[1]->Td,p->Td);
        }return;
    }
    ll query(const vector<Point> &v){
        int l = 0,r = v.size()-1;
        while(l + 3 <= r){
            int midx = (l+l+r)/3;
            int midy = (l+r+r)/3;
            if((v[midx]*op[nowpos].p) > (v[midy]*op[nowpos].p)) r = midy;
            else l = midx;
        }
        ll ret = -(1LL<<60);
        for(int i=l;i<=r;++i) ret = max(ret,v[i]*op[nowpos].p);
        return ret;
    }
    ll queryu(Node *p,int l,int r){
        if(op[nowpos].l <= l && r <= op[nowpos].r) return query(p->Tu);
        int mid = (l+r) >> 1;
        if(op[nowpos].r <= mid) return queryu(p->ch[0],l,mid);
        if(op[nowpos].l >  mid) return queryu(p->ch[1],mid+1,r);
        return max(queryu(p->ch[0],l,mid),queryu(p->ch[1],mid+1,r));
    }
    ll queryd(Node *p,int l,int r){
        if(op[nowpos].l <= l && r <= op[nowpos].r) return query(p->Td);
        int mid = (l+r) >> 1;
        if(op[nowpos].r <= mid) return queryd(p->ch[0],l,mid);
        if(op[nowpos].l >  mid) return queryd(p->ch[1],mid+1,r);
        return max(queryd(p->ch[0],l,mid),queryd(p->ch[1],mid+1,r));
    }
    ll lastans = 0;
    #define decode(x) (x = (x^(lastans & 0x7fffffff)))
    int main(){
        char ch;int cnt = 0;
        int n;read(n);while(ch=getchar(),ch<'!');
        bool e = true;if(ch == 'E') e = false;
        for(int i=1;i<=n;++i){
            while(ch=getchar(),ch<'!');op[i].cmd = ch == 'A';
            if(op[i].cmd){
                ++cnt;read(op[i].p.x);read(op[i].p.y);
                op[i].id = cnt;
            }else{
                read(op[i].p.x);read(op[i].p.y);
                read(op[i].l);read(op[i].r);
            }
        }
        for(int i=1;i<=n;++i){
            if(op[i].cmd){
                if(e) decode(op[i].p.x),decode(op[i].p.y);
                nowpos = i;
                insert(root,1,cnt);
            }else{
                if(e){
                    decode(op[i].p.x);decode(op[i].p.y);
                    decode(op[i].l);decode(op[i].r);
                }
                nowpos = i;
                if(op[i].p.y > 0) lastans = queryu(root,1,cnt);
                else lastans = queryd(root,1,cnt);
                //lastans = max(queryd(root,1,cnt),queryu(root,1,cnt));
                printf("%lld
    ",lastans);
            }
        }
        getchar();getchar();
        return 0;
    }
    

    但貌似官方题解有更巧妙的做法...

  • 相关阅读:
    angular6跨域问题proxy.conf.json
    angular2 防止刷新页面 参数丢失
    自定义修改table样式 scoped会影响
    angular ngfor和ngif指令共用
    yum 是轮船发动机,brew 是汽车发动机,不能混用。
    Vue watch 监听 computed
    vue 路由跳转,参数消失问题
    vue 使用:class切换高亮 点击路由跳转 上个组件的点击事件保存的参数 在下一次重复进入这个组件的时候 默认值都已经还原了 得通过路由跳转的时候 把上个组件的状态通过路由保存下来 通过下一次进入这个组件的时候 获取路由 渲染当前页面的:class 进行高亮
    函数防抖 函数节流
    vue router-view router-link RouterView【命令视图】和RouterLink【命令路线】本身是两个组件。 命名路由
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6438266.html
Copyright © 2020-2023  润新知