【uoj#191.】Unknown

论文题,手残+脑残根本写不出来点分写法。

论文里5.14好像有个优雅的写法。

考虑用线段树维护凸包,1操作就是往线段树最底层加点,每把一根线段加满就合并。这样显然是不行的,只要在一个点左右横跳就会t。

然后考虑每次不立即合并,而是等到下一次同层的线段需要合并的时候再进行合并,这样不管怎么搞都是nlog2n。具体势能分析不会,所以就简单证一下。

插入&删除时,考虑合并一条长度为L的线段,至少要进行L次插入,平均下来对每层的贡献就是O(1),共logn层,所以每次的复杂度是logn的,总复杂度nlogn

查询时,考虑一个区间会被分成log条线段,考虑每条线段的情况:

1、已经被合并

2、没有被合并,两个子区间已经合并。

3、没有被合并,左子区间已经被合并。

由于只会在右端插入,所以左区间肯定比右区间先合并,所以最坏情况下只需要递归右区间。

1、2都是O(1)直接求,3需要递归,共log层,单次查询复杂度log2n,总复杂度nlog2n。

uoj上好像并没有把空间卡到64M;

#include<bits/stdc++.h>
#define maxn 5000005
#define ll long long
#define INF 1ll<<62
#define MOD 998244353

using namespace std;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

const int n=524288;

struct P{
    int x,y;
    P(int x,int y):x(x),y(y){};
    P(){};
    bool operator < (const P &tmp)const{if(x==tmp.x)return y<tmp.y;return x<tmp.x;}
}pool[maxn],*tt,*a[n<<1];

ll Cross(P a,P b){return 1ll*a.x*b.y-1ll*a.y*b.x;}

inline int calc(P a,P b,P c){
    int up1=b.y-a.y,up2=c.y-b.y;
    int down1=b.x-a.x,down2=c.x-b.x;
    return 1ll*up1*down2<=1ll*up2*down1;
}

inline int calc2(P a,P b,P c){
    int up1=b.y-a.y,up2=c.y;
    int down1=b.x-a.x,down2=c.x;
    return 1ll*up1*down2>=1ll*up2*down1;
}

inline void push(P *a,int &ta,P p){
    while(ta>1&&calc(a[ta-1],a[ta],p))--ta;
    a[++ta]=p;
}

int TOT;

inline void merge(P *&a,int &ta,P *b,int tb,P *c,int tc){
    a=tt;ta=0;
    int t1=1,t2=1;
    while(t1<=tb||t2<=tc){
        if(t1<=tb){
            if(t2>tc||b[t1]<c[t2])push(a,ta,b[t1++]);
            else push(a,ta,c[t2++]);
        }else push(a,ta,c[t2++]);
    }
    tt+=ta;
}

int tot[maxn],last[maxn];

inline void insert(int o,int l,int r,int x,int dep,P v){
    if(l==r){
        a[o]=tt++;tt->x=v.x;tt->y=v.y;tot[o]=1;
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)insert(o<<1,l,mid,x,dep+1,v);
    else insert(o<<1|1,mid+1,r,x,dep+1,v);
    if(x==r){
        if(last[dep]){
            int t=last[dep];
            merge(a[t],tot[t],a[t<<1],tot[t<<1],a[t<<1|1],tot[t<<1|1]);
        }
        last[dep]=o;
    }
}

inline void erase(int o,int l,int r,int x,int dep){
    tot[o]=0;
    if(l==r)return;
    if(last[dep]==o)last[dep]=0;
    int mid=l+r>>1;
    if(x<=mid)erase(o<<1,l,mid,x,dep+1);
    else erase(o<<1|1,mid+1,r,x,dep+1);
}

inline ll query(P *a,int tot,P p){
    int l=1,r=tot;
    while(l<=r){
        int mid=l+r>>1;
        if(mid==tot)return Cross(p,a[mid]);
        if(calc2(a[mid],a[mid+1],p))l=mid+1;
        else r=mid-1;
    }
    return Cross(p,a[l]);
}

ll Max;

inline void query(int o,int l,int r,int x,int y,P v){
    if(tot[o]&&x<=l&&r<=y){
        Max=max(Max,query(a[o],tot[o],v));
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)query(o<<1,l,mid,x,y,v);
    if(y>mid)query(o<<1|1,mid+1,r,x,y,v);
}

int m,Ans;

void WoRk(){
    int type,f1,f2,f3,f4;
    for(int i=1;i<=m;++i){
        type=read();
        if(type==1){
            f1=read();f2=read();
            insert(1,1,n,++TOT,1,P(f1,f2));
        }else
        if(type==2){
            erase(1,1,n,TOT--,1);
        }else{
            f1=read();f2=read();f3=read();f4=read();
            Max=-INF;query(1,1,n,f1,f2,P(f3,f4));
            Ans^=(Max%MOD+MOD)%MOD;
        }
    }
    printf("%d\n",Ans);
}

void Init(){
    tt=pool;TOT=Ans=0;
    memset(last,0,sizeof(last));
    memset(tot,0,sizeof(tot));
}

int main(){
    int Illyasviel_Von_Einzbern=read();
    for(;;){
        m=read();
        if(m==0)return 0;
        Init();
        WoRk();
    }
    return 0;
}

 

posted @ 2017-10-20 10:14  Illya  阅读(360)  评论(2编辑  收藏  举报