FJoi2017 1月21日模拟赛 comparison(平衡树+thita重构)

题目大意:

经黄学长指出,此题原题出自2014湖北省队互测 没有人的算术

规定集合由二元组(A,B)构成,A、B同时也是两个这样的集合,即A、B本身也是二元组

规定二元组S为严格最小集合,S=(S,S),规定T为严格最大集合T=(T,T)

刚开始我们有两个集合S和T,即全局最小集合和全局最大集合,编号分别为0,n+1

下面我们规定集合的比较规则,是递归定义的

我们称集合X(X1,X2)等于Y(Y1,Y2)当且仅当

X1=Y1 并且 X2=Y2

我们称集合X(X1,X2)小于Y(Y1,Y2)当且仅当

1.X1<Y1

2.X1==Y1 且 X2<Y2

现在有n个操作:

1.将集合u、v合并为新二元组集合X(u,v)

2.输出所有小于或等于X的集合数量

输入

第一行一个整数n,代表有n个操作

下面n行,每行2个数u、v代表将集合u、v组合成新的集合

输出

共n行,每行一个整数,代表当前全集中小于或等于当前新生成集合的数量

样例输入

30
31 0
0 31
0 1
3 3
3 4
4 2
3 4
31 3
2 2
5 3
9 4
8 1
9 12
13 5
13 12
13 0
3 12
4 3
15 18
16 16
11 5
14 17
9 20
20 18
16 10
31 24
20 7
7 5
14 21
24 4

样例输出

2
2
2
4
5
6
6
9
7
9
10
11
11
12
13
12
7
9
17
17
14
19
13
22
19
27
23
12
23
27

Solution

orz神犇wwx

法一:

先考虑最暴力的做法,那就是O(n*n)的递归比较

得分10

法二:

考虑将集合维护成一个有序序列,用插入排序O(n)解决一个点的插入,就可以O(1)得出答案,比较就是比数组下标就行了哦

得分30

法三:

显然可以用平衡树维护大小关系嘛,把原来数组变成一个映射,将下标映射到区间[0,oo)上记为Val,其中S取0,T去oo,插入时,若集合X大小在A、B间,则Val(X)=(Val(A)+Val(B))/2

那么,每次插入后为了维护Val,就要重构遍平衡树

得分100

下面是标解

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define MaxN 50010
#define MaxBuf 1<<22
#define inf LONG_LONG_MAX/2
#define mid ((l>>1)+(r>>1)+(l&r&1))
#define RG register
#define inline __inline__ __attribute__((always_inline))
#define Blue() ((S==T&&(T=(S=B)+fread(B,1,MaxBuf,stdin),S==T))?0:*S++)

char B[MaxBuf],*S=B,*T=B;

template<class Type>inline void Rin(RG Type &x){
    x=0;RG int c=Blue();RG bool b=false;
    for(;c<48||c>57;c=Blue())
        if(c==45)b=true;
    for(;c>47&&c<58;c=Blue())
        x=(x<<1)+(x<<3)+c-48;
    if(b)x=-x;
}

int n,ans;
struct Treap{
#define L long long
    struct Nt{
        Nt *ch[2],*s1,*s2;
        int size,k;
        L v;

        inline void pud() {size=ch[0]->size+ch[1]->size+1;}
    }pool[MaxN],*null,*root,*Re_p;

    L Re_s,Re_t;

    inline void rotate(RG Nt *&o,RG bool d){
        RG Nt *k=o->ch[d];
        o->ch[d]=k->ch[!d];
        k->ch[!d]=o;
        o->pud();
        k->pud();
        o=k;
    }

    void insert(RG Nt *&o,RG Nt *p,RG L l,RG L r){
        if(o==null){
                o=p;
            p->k=rand()*2333+rand(); p->v=mid; p->size=1;
            printf("%d\n",ans);
            return;
        }
        RG bool d=(p->s1->v > o->s1->v) || (p->s1->v == o->s1->v && p->s2->v >= o->s2->v);
        d? (ans+=o->ch[0]->size+1,insert(o->ch[1],p,o->v+1,r)):(insert(o->ch[0],p,l,o->v-1));
        if(o->ch[d]->k < o->k)rotate(o,d),Re_p=o,Re_s=l,Re_t=r;
        o->pud();
    }

    void Relabel(Nt *o,L l,L r){
        if(o==null)return;
        o->v=mid;
        Relabel(o->ch[0],l,o->v-1);
        Relabel(o->ch[1],o->v+1,r);
    }
public:
    void init(){
        root=null=pool+n+2;
        null->ch[0]=null->ch[1]=null;
        pool->v=0;
        (pool+n+1)->v=inf+1;
    }

    inline void insert(RG int cnt,RG int u,RG int v){
        ans=2;
        pool[cnt].s1=pool+u;
        pool[cnt].s2=pool+v;
        pool[cnt].ch[0]=pool[cnt].ch[1]=null;
        Re_p=null;
        insert(root,pool+cnt,1,inf);
        Relabel(Re_p,Re_s,Re_t);
    }
}RT;

#define set_file(File) {freopen(#File".in","r",stdin); freopen(#File".out","w",stdout);}
#define close_file() {fclose(stdin); fclose(stdout);}

int main(){
    srand('K'+'a'+'i'+'b'+'a');

    set_file(comparison);

    Rin(n); RT.init();
    for(RG int i=1,u,v;i<=n;i++){
        Rin(u),Rin(v);
        RT.insert(i,u,v);
    }

    close_file();

    return 0;
}

 

posted @ 2017-01-21 21:11  keshuqi  阅读(416)  评论(0编辑  收藏  举报