bzoj3533: [Sdoi2014]向量集

Description

维护一个向量集合,在线支持以下操作:
"A x y (|x|,|y| < =10^8)":加入向量(x,y);
" Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T,其中T为已经加入的向量个数)询问第L个到第R个加入的向量与向量(x,y)的点积的最大值。
    集合初始时为空。

Input

输入的第一行包含整数N和字符s,分别表示操作数和数据类别;
    接下来N行,每行一个操作,格式如上所述。
    请注意s≠‘E‘时,输入中的所有整数都经过了加密。你可以使用以下程序
得到原始输入:
inline int decode (int x long long lastans) {
     return x ^ (lastans & Ox7fffffff);
}
function decode
begin
    其中x为程序读入的数,lastans为之前最后一次询问的答案。在第一次询问之前,lastans=0。

注:向量(x,y)和(z,W)的点积定义为xz+yw。

Output

对每个Q操作,输出一个整数表示答案。

将向量看作平面上的点,线段树维护上、下凸包,在凸包上三分可得到最优解。对线段树的每个区间,当区间内向量都已读入时计算凸包。

#include<cstdio>
#include<algorithm>
typedef long long i64;
char buf[5000000],*ptr=buf,*pmx=buf+5000000;
const i64 inf=1ll<<62;
const int N=1e7;
int g(){
    if(ptr==pmx)fread(ptr=buf,1,5000000,stdin);
    return *ptr++;
}
int _(){
    int x=0,f=1,c=g();
    while(c<48||c>57)c==‘-‘&&(f=-1),c=g();
    while(c>47&&c<58)x=x*10+c-48,c=g();
    return x*f;
}
int _c(){
    int c=g();
    while(c<‘A‘||c>‘Z‘)c=g();
    return c;
}
void maxs(i64&a,i64 b){if(a<b)a=b;}
void maxs(int&a,int b){if(a<b)a=b;}
void mins(int&a,int b){if(a>b)a=b;}
struct pos{
    int x,y;
    i64 operator()(pos a){
        return i64(x)*a.x+i64(y)*a.y;
    }
}mem[21000007],*mp=mem;
pos operator-(pos a,pos b){
    return (pos){a.x-b.x,a.y-b.y};
}
i64 operator*(pos a,pos b){
    return i64(a.x)*b.y-i64(a.y)*b.x;
}
bool operator<(pos a,pos b){
    return a.x!=b.x?a.x<b.x:a.y<b.y;
}
struct node{
    pos*l,*r;
    void init(int x,int y){
        l=mp;
        *mp++=(pos){x,y};
        r=mp;
    }
    void ins(pos x){
        if(mp>l&&mp[-1].x==x.x)--mp;
        while(mp-l>=2&&(x-mp[-1])*(mp[-2]-mp[-1])>=0)--mp;
        *mp++=x;
    }
    void init(node a,node b){
        if(!a.l)*this=b;
        else if(!b.l)*this=a;
        else{
            l=mp;
            pos*ap=a.l,*bp=b.l;
            while(ap!=a.r&&bp!=b.r){
                if(*ap<*bp)ins(*ap++);
                else ins(*bp++);
            }
            while(ap!=a.r)ins(*ap++);
            while(bp!=b.r)ins(*bp++);
            r=mp;
        }
    }
    i64 find(pos x){
        if(!l)return -1ll<<62;
        i64 v1,v2;
        int L=0,R=r-l-1,M1,M2;
        while(R-L>3){
            M1=L+R>>1;
            M2=M1+1;
            if(x(l[M1])<x(l[M2]))L=M1;
            else R=M2;
        }
        for(v1=x(l[L++]);L<=R;++L)maxs(v1,x(l[L]));
        return v1;
    }
}us[1051111],ds[1051111];
bool d[1051111];
int n,de,la=0,x,y,l,r,id=0;
int main(){
    n=_();de=_c()!=‘E‘;
    for(int i=0;i<n;++i){
        if(_c()==‘A‘){
            x=_();y=_();++id;
            if(de)x^=la,y^=la;
            int w=id+524288;
            us[w].init(x,y);
            ds[w].init(x,-y);
            d[w]=1;
            for(w>>=1;w&&d[w<<1^1];w>>=1){
                us[w].init(us[w<<1],us[w<<1^1]);
                ds[w].init(ds[w<<1],ds[w<<1^1]);
                d[w]=1;d[w<<1^1]=0;
            }
        }else{
            x=_();y=_();l=_();r=_();
            if(de)x^=la,y^=la,l^=la,r^=la;
            i64 ans=-1ll<<62;
            pos p1=(pos){x,y},p2=(pos){x,-y};
            for(l+=524287,r+=524289;l^r^1;l>>=1,r>>=1){
                if(~l&1)maxs(ans,us[l^1].find(p1)),maxs(ans,ds[l^1].find(p2));
                if(r&1)maxs(ans,us[r^1].find(p1)),maxs(ans,ds[r^1].find(p2));
            }
            printf("%lld\n",ans);
            la=ans&0x7fffffff;
        }
    }
    return 0;
}
时间: 2024-10-26 04:33:23

bzoj3533: [Sdoi2014]向量集的相关文章

BZOJ3533 [Sdoi2014]向量集 【线段树 + 凸包 + 三分】

题目链接 BZOJ3533 题解 我们设询问的向量为\((x_0,y_0)\),参与乘积的向量为\((x,y)\) 则有 \[ \begin{aligned} ans &= x_0x + y_0y \y &= -\frac{x_0}{y_0}x + \frac{ans}{y_0} \\end{aligned} \] 所以向量集里的向量实际上可以对应到平面上一组点,我们用一个斜率固定的直线去经过这些点,使得斜率最大或最小 当\(y_0 > 0\)时,要求截距最大 当\(y_0 <

bzoj3533【SDOI2014】向量集

3533: [Sdoi2014]向量集 Time Limit: 25 Sec  Memory Limit: 512 MB Submit: 669  Solved: 213 [Submit][Status][Discuss] Description 维护一个向量集合,在线支持以下操作: "A x y (|x|,|y| < =10^8)":加入向量(x,y); " Q x y l r (|x|,|y| < =10^8,1 < =L < =R < =T

BZOJ 3533 sdoi 2014 向量集

设(x,y)为Q的查询点,分类讨论如下:1.y>0:  最大化a*x+b*y,维护一个上凸壳三分即可 2.y<0:最大化a*x+b*y  维护一个下凸壳三分即可 我们考虑对时间建出一棵线段树 对于每个区间,如果满了就做出两个凸壳 总时间复杂度是O(n*log^2n) 之后我们考虑查询,每个区间最多被分解为log(n)个区间 在每个区间的凸壳上三分最优解即可 至于优化,可以设定一个阈值,当区间长度小于阈值时不用做凸壳,查询时直接暴力就可以了 #include<cstdio> #inc

瞎题表

数据结构小练习bzoj3221:[Codechef FEB13] Obserbing the tree树上询问 树剖+主席树(区间修改,加等差数列)bzoj2735:世博会 主席树+切比雪夫距离转曼哈顿距离+我最弱的数学推理bzoj3217:ALOEXT 替罪羊套01Trie(我的码力还是弱得不行,傻逼错误一大堆……)精细的实现果然很重要(对于数据结构里的点(比如……),可以直接提取其维护的区间然后操作的啊)替罪羊的插入重建好像使得重建点的祖先的cover不正确了?然而并没有什么影响?(zyf提

YCB 的暑期计划

前言 YCB现在很弱(TAT) 暑假有一个月,赶快狂补一下. 大概的计划如下: 首先前期会以数据结构为主,毕竟代码能力太弱,涉及内容:线段树分治.二进制分组.KD-Tree. 等数据结构做到没有智商的时候加入一波数论,内容为 杜教筛.min_25筛. 然后中途小清新一下,做一些 组合博弈与构造题. 接着继续练代码能力,顺便学一些神奇的暴力:启发式合并.dsu on tree . 然后图论也忘的差不多了,就回过头去学点新东西,大概会有spfa判负环.0/1分数规划.差分约束. 估计这个时候也没有什

BZOJ 4311 向量

shallot+向量集 混合版? 首先我们考虑每个向量的存在时间为[L,R] 那么我们知道任意一个区间在线段树上最多被分解成logn个区间 那么我们可以像shallot一样进行区间覆盖 注意到本题的查询是在凸壳上完成的,而凸壳不像shallot的线性基一样有固定的时间复杂度 但是本题的查询是可分离的,那么我们不需要将向量下传,只需要在线段树的每一层做凸壳即可 查询时每走一层对该层三分取最优解,建造凸壳和三分方法同向量集 QAQ 上午因为排序不小心写反了符号调了好久 QAQ 时间复杂度O(nlog

洛谷 P3390 【模板】矩阵快速幂

这题的确是个模板 但也要提到有关矩乘的内容: 首先什么是矩阵? 给一个线性变换 F(x)   (她可能就是个函数,定义域为向量集) 她可以把一个N维向量变成M维 那么显然x的每一维都可能影响着F(x)的每一维,于是F(x)这个线性变换就应该是N*M个在每两维间的小映射构成的. 于是我们可以把她写成M行N列的矩阵(M行N列是出于习惯) 所以矩阵是用于形象的表示线性变换的工具: 所以怎么合乎习惯的构造矩阵呢? 举例说明: 如,有一个三元组(3维向量)x{a,b,c} 定义F(x)={a+b,b+c}

利用算法识别车厘子与樱桃

引言:朴素贝叶斯分类器作为基础的分类算法,早在基础数学时期就已经被使用,目前在各行各业中更是被广泛使用.近几年车厘子在中国地区卖得火热,面对车厘子和樱桃,很多老百姓很难分清楚,那么算法能帮我们区分吗? 本文选自<大数据时代的算法:机器学习.人工智能及其典型实例>. 车厘子是樱桃吗?它们有区别是什么呢?通过在水果市场采集,获得了一些关于车厘子和樱桃的相关特征数据.  通过现有的车厘子和樱桃的数据,在包含车厘子和樱桃的混合水果中,随机给一个车厘子或者樱桃,识别它是樱桃或者车厘子的可能性哪个大? 本

【甘道夫】用贝叶斯文本分类测试打过1329-3.patch的Mahout0.9 on Hadoop2.2.0

引言 接前一篇文章<[甘道夫]Mahout0.9 打patch使其支持 Hadoop2.2.0> http://blog.csdn.net/u010967382/article/details/39088035, 为Mahout0.9打过Patch编译成功后,使用贝叶斯文本分类来测试Mahout0.9对Hadoop2.2.0的兼容性. 欢迎转载,转载请注明出处: http://blog.csdn.net/u010967382/article/details/39088285 步骤一:将20ne