ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

 小C正在出一道题...因为语文水平有限他想不出复杂的背景,所以以下就是题意了。
  平面上有N个点,开始时每个点属于一个不同的集合。不妨设点Pi属于集合Si。请维护数据结构支持以下三种操作:
  "Merge x y":将集合Sy中的点到Sx中;
  "Split i d v"(d ∈ {0, 1}):创建新集合Sc + 1,Sc + 2,之后将集合Si中的所有点中,第d维坐标不超过v的到集合Sc + 1中,超过v的移动到集合Sc + 2中,其中c为现有集合数( 包括之前合并和分割中产生的空集 );
  "Query i":查询集合Si中点权值的最大值,最小值及和;
  "Add i d":将集合Si中所有点的权值增加d。
  方便起见,对于d ∈ {0, 1},输入的所有点的第d维坐标不重复。所有操作涉及的集合非空。

Input

  第一行一个整数N表示点数。
  接下来N行,每行3个整数分别表示Pi的坐标与权值。
  接下来一个整数Q表示操作数。
  接下来Q行,每行描述一个操作,格式如上所述。

Output

  对于每个Q操作,输出三个整数,依次表示询问集合权值的最大值,最小值与和。
预处理出点集的一颗二维k-d tree
将每个点到根的路径复制出来作为初始状态
由于树形态相同,合并和分裂可以仿照线段树
分裂时增加的点数$T(n)=2T(\frac{n}{4})+O(1)=O(\sqrt{n})$
合并复杂度与减少的点数同阶
因此总时间复杂度$O(q\sqrt{n})$
由每个点到根的路径长度之和可得空间复杂度的上界$O(nlogn)$
#include<bits/stdc++.h>
#define G getchar()
int _(){
    int x=0,f=1,c=G;
    while(c<48)c=='-'&&(f=-1),c=G;
    while(c>47)x=x*10+c-48,c=G;
    return x*f;
}
int _s(){
    int c=G,c0;
    while(c<33)c=G;
    c0=c;
    while(c>32)c=G;
    return c0;
}
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
const int N=100007,inf=0x3f3f3f3f;
int n,qp;
struct node;
node*newnode();
struct node{
    node*c[2];
    int mn[2],mx[2];
    int mnv,mxv,sz,id;
    long long sum,a;
    void add(long long x){
        if(this){
            a+=x;
            mnv+=x;
            mxv+=x;
            sum+=x*sz;
        }
    }
    void dn(){
        if(a){
            c[0]->add(a);
            c[1]->add(a);
            a=0;
        }
    }
    void up(){
        mnv=inf;mxv=-inf;sum=0;
        sz=0;
        if(c[0]){
            mnv=c[0]->mnv;
            mxv=c[0]->mxv;
            sum=c[0]->sum;
            sz=c[0]->sz;
        }
        if(c[1]){
            mnv=min(mnv,c[1]->mnv);
            mxv=max(mxv,c[1]->mxv);
            sum+=c[1]->sum;
            sz+=c[1]->sz;
        }
    }
    void set(int x0,int x1,int v){
        mn[0]=mx[0]=x0;
        mn[1]=mx[1]=x1;
        sum=mnv=mxv=v;
        sz=1;a=0;
    }
    void query(){
        printf("%d %d %lld\n",mxv,mnv,sum);
    }
    void upds(){
        for(int i=0;i<2;++i){
            mn[i]=min(c[0]->mn[i],c[1]->mn[i]);
            mx[i]=max(c[0]->mx[i],c[1]->mx[i]);
        }
    }
}mem[N*30],*pool[N*30],*rt0,*n0[N],*rts[N*3];
int pp;
node*newnode(){
    return pool[--pp];
}
int dx=0;
bool cmp(node*a,node*b){
    return a->mn[dx]<b->mn[dx];
}
node*build(int L,int R){
    if(L==R)return n0[L];
    int M=(L+R)>>1;
    std::nth_element(n0+L,n0+M,n0+R+1,cmp);
    node*w=newnode();
    dx^=1;
    w->c[0]=build(L,M);
    w->c[1]=build(M+1,R);
    w->upds();
    dx^=1;
    return w;
}
node*ss[50];
int sp=0;
void init(node*w){
    ss[sp++]=w;
    if(w->id){
        node*t=w;
        for(int i=sp-2;~i;--i){
            node*u=newnode();
            *u=*ss[i];
            int d=u->c[1]==ss[i+1];
            u->c[d]=t;
            u->c[d^1]=0;
            u->up();
            t=u;
        }
        rts[w->id]=t;
    }else{
        init(w->c[0]);
        init(w->c[1]);
    }
    --sp;
}
int _x,_d;
void split(node*w,node*&l,node*&r){
    if(!w)l=r=0;
    else if(_x<w->mn[_d])l=0,r=w;
    else if(w->mx[_d]<=_x)l=w,r=0;
    else{
        w->dn();
        node*u=newnode();
        *u=*w;
        split(w->c[0],w->c[0],u->c[0]);
        split(w->c[1],w->c[1],u->c[1]);
        w->up();u->up();
        l=w,r=u;
    }
}
node*merge(node*a,node*b){
    if(!a)return b;
    if(!b)return a;
    a->dn();b->dn();
    a->c[0]=merge(a->c[0],b->c[0]);
    a->c[1]=merge(a->c[1],b->c[1]);
    a->up();
    pool[pp++]=b;
    return a;
}
int main(){
    n=_();
    pp=n*30;
    for(int i=0;i<pp;++i)pool[i]=mem+i;
    for(int i=1,x,y;i<=n;++i){
        x=_();y=_();
        n0[i]=newnode();
        n0[i]->set(x,y,_());
        n0[i]->id=i;
    }
    rt0=build(1,n);
    init(rt0);
    for(qp=_();qp;--qp){
        int o=_s();
        if(o=='M'){
            int x=_(),y=_();
            rts[x]=merge(rts[x],rts[y]);
            rts[y]=0;
        }else if(o=='S'){
            int x=_();
            _d=_();_x=_();
            split(rts[x],rts[n+1],rts[n+2]);
            rts[x]=0;
            n+=2;
        }else if(o=='Q'){
            rts[_()]->query();
        }else{
            int x=_();
            rts[x]->add(_());
        }
    }
    return 0;
}

 

posted on 2017-04-17 16:55  nul  阅读(251)  评论(0编辑  收藏  举报