SDOI 2014 向量集

[SDOI2014]向量集

題目描述

維護一個向量集合,在線支持如下操做: - "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)的點積的最大值。 集合初始時爲空。

輸入輸出格式

輸入格式

 

輸入的第一行包含整數N和字符s,分別表示操做數和數據類別; 接下來N行,每行一個操做,格式如上所述。 請注意s≠'E'時,輸入中的全部整數都通過了加密。你可使用如下程序獲得原始輸入: ··· inline int decode (int x long long lastans) { return x ^ (lastans & Ox7fffffff); } ``` 其中x爲程序讀入的數,lastans爲以前最後一次詢問的答案。在第一次詢問以前,lastans=0。注:向量(x,y)和(z,W)的點積定義爲xz+yw。

輸出格式

 

對每一個Q操做,輸出一個整數表示答案。

輸入輸出樣例

輸入樣例 #1

6 A
A 3 2
Q 1 5 1 1
A 15 14
A 12 9
Q 12 8 12 15
Q 21 18 19 18

輸出樣例 #1

13
17
17

說明

樣例解釋:解密以後的輸入爲 ``` 6 E A 3 2 Q 1 5 1 1 A 2 3 A 1 4 Q 1 5 1 2 Q 4 3 2 3 ``` 1 < =N < =4\*10^5

 

 

 

 

[題意]

維護向量序列,支持在序列末尾添加向量,以及詢問某個區間中的向量與給定向量的點積的最大值。算法

[官方題解]

 

[我的題解](網上東拼西湊的)


通常性設當前詢問的$y_0>0$,那麼$\dfrac{ans}{y_0}=\max\{\dfrac{x_0}{y_0}\cdot x+y\}$,而後這個東西和斜率優化長得同樣,答案必定是在凸殼上的.優化

因而咱們維護這個凸殼.由於有區間詢問因此線段樹維護每一個區間的凸殼.具體地,插入的時候統計當前區間已經有多少個點,若是點數等於當前區間長度那麼構造出這個區間的凸殼.詢問的時候拆成$\log$個區間分別跑二分/三分便可.加密

求凸包這裏使用按$x$座標排序的那個算法.注意若是幾個點的$x$相同那麼要按$y$排序.spa

插入的時候每一個區間只會被構建一次凸包,總複雜度$O(n\log n)$,排序用歸併.3d

查詢的時候拆成$\log$個區間,每一個區間$O(\log n)$三分/二分,總複雜度$O(n\log ^2 n)$指針

每一個區間都要構建一次凸包,能夠這麼處理:每一個線段樹節點放個指針,動態開闢空間創建凸包。code

網上很多代碼把狀況討論合併成一種,只維護上凸殼。保險起見,也爲了本身可以更好地理解,我仍是分類討論,同時維護上下凸殼。blog

 

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
    register char ch=getchar();x=0;register bool f=0;
    for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    if(f) x=-x;
}
const int N=4e5+3;
int n,m,cnt;ll ans;char type[3],op[3];
struct Q{
    int opt,l,r,x,y;
    Q(){}
    Q(int opt,int l,int r,int x,int y):opt(opt),l(l),r(r),x(x),y(y){}
}q[N];
struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){}
    point operator +(const point &a)const{
        return point(x+a.x,y+a.y);
    }
    point operator -(const point &a)const{
        return point(x-a.x,y-a.y);
    }
    ll operator *(const point &a)const{
        return (ll)x*a.x+(ll)y*a.y;
    }
    ll operator ^(const point &a){
        return (ll)x*a.y-(ll)y*a.x;
    }
    bool operator <(const point &a)const{
        return x==a.x?y<a.y:x<a.x;
    }
}p[N],tmp[N];int tmpsize;
struct CH{
    point *up,*dw;
    int upsize,dwsize;
    void init(int l,int r){
        up=new point[r-l+2];
        dw=new point[r-l+2];
        tmpsize=upsize=dwsize=0;
        for(int i=l;i<=r;i++) tmp[++tmpsize]=p[i];
        sort(tmp+1,tmp+tmpsize+1);
        for(int i=1;i<=tmpsize;i++){
            for(;upsize>1&&((tmp[i]-up[upsize])^(up[upsize]-up[upsize-1]))<=0;upsize--);
            up[++upsize]=tmp[i];
            for(;dwsize>1&&((dw[dwsize]-dw[dwsize-1])^(tmp[i]-dw[dwsize]))<=0;dwsize--);
            dw[++dwsize]=tmp[i];
        }
    }
    ll qmax(point p){
        int l,r,mid1,mid2;ll res=-(1LL<<62);
        if(p.y>=0){
            l=1;r=upsize;
            while(r-l>2){
                mid1=l+(r-l)/3;
                mid2=r-(r-l)/3;
                if(up[mid1]*p<up[mid2]*p)
                    l=mid1;
                else
                    r=mid2;
            }
            for(int i=l;i<=r;i++) res=max(res,up[i]*p);
        }
        else{
            l=1;r=dwsize;
            while(r-l>2){
                mid1=l+(r-l)/3;
                mid2=r-(r-l)/3;
                if(dw[mid1]*p<dw[mid2]*p)
                    l=mid1;
                else
                    r=mid2;
            }
            for(int i=l;i<=r;i++) res=max(res,dw[i]*p);
        }
        return res;
    }
}b[N<<2];bool tag[N<<2];
#define lch k<<1
#define rch k<<1|1
ll query(int k,int l,int r,int x,int y,point p){
    if(l==x&&r==y){
        if(!tag[k]) tag[k]=1,b[k].init(l,r);
        return b[k].qmax(p);
    }
    int mid=l+r>>1;
    if(y<=mid) return query(lch,l,mid,x,y,p);
    else if(x>mid) return query(rch,mid+1,r,x,y,p);
    else return max(query(lch,l,mid,x,mid,p),query(rch,mid+1,r,mid+1,y,p));
}
inline void decode(int &x){
    if(type[0]=='E') return ;
    x=x^(ans&0x7fffffff);
}
int main(){
    read(m);scanf("%s",type);
    for(int i=1,opt,x,y,l,r;i<=m;i++){
        scanf("%s",op);opt=(op[0]=='Q');
        if(opt){
            read(x);read(y);
            read(l);read(r);
        }
        else{
            read(x);read(y);l=r=0;
            ++n;
        }
        q[i]=Q(opt,l,r,x,y);
    }
    for(int i=1,l,r,x,y;i<=m;i++){
        if(q[i].opt){
            l=q[i].l;r=q[i].r;
            x=q[i].x;y=q[i].y;
            decode(l);decode(r);
            decode(x);decode(y);
            ans=query(1,1,n,l,r,point(x,y));
            printf("%lld\n",ans);
        }
        else{
            x=q[i].x;y=q[i].y;
            decode(x);decode(y);
            p[++cnt]=point(x,y);
        }
    }
    return 0;
}

 

收穫:排序

全部形如$f[i]=\min\limits_{L(i)\leq j\leq R(i)}\{k(i)x(j)+F(j)\}+G(i)$的$dp$都是可作的(斜率優化型動態規劃)get

相關文章
相關標籤/搜索