BZOJ 4399 魔法少女LJJ 線段樹合併

題目大意:第一行有一個正整數m,表示操作個數。
接下來m行,每行先給出1個正整數c。
若c=1,之後一個正整數x,表示新建一個權值爲x的節點,並且節點編號爲n+1(當前有n個節點)。
若c=2,之後兩個正整數a,b,表示在a,b之間連接一條邊。
若c=3,之後兩個正整數a,x,表示a聯通塊內原本權值小於x的節點全部變成x。
若c=4,之後兩個正整數a,x,表示a聯通塊內原本權值大於x的節點全部變成x。
若c=5,之後兩個正整數a,k,表示詢問a所屬於的聯通塊內的第k小的權值是多少。
若c=6,之後兩個正整數a,b,表示詢問a所屬聯通塊內所有節點權值之積與b所屬聯通塊內所有節點權值之積的大小,
若a所屬聯通塊內所有節點權值之積大於b所屬聯通塊內所有節點權值之積,輸出1,否則爲0。
若c=7,之後一個正整數a,表示詢問a所在聯通塊大小
若c=8,之後兩個正整數a,b,表示斷開a,b所連接的邊。
若c=9,之後一個正整數a,表示斷開a點的所有連邊
c<=7

將一個聯通塊合併刪除,可以建權值線段樹,動態開點,使用線段樹合併。
3、4操作即插入 等於大於/小於x的數的個數 的x,然後將小於/大於x的數全部刪除。
6操作可以將乘積轉爲對數加法(不過好像不轉也可以..),反正也只是比較大小..
好像不寫內存回收會爆炸的把..在delete以後一定再賦值成NULL

#include <cstdio>
#include <cmath>
#include <deque>
#define N 400001
#define M 1000000000
using namespace std;
deque<void*> recycle;
struct Node {
    Node* ch[2];
    int siz;
    double sum;
    Node() {
        ch[0]=ch[1]=NULL;
        sum=0;
        siz=0;
    }

    void* operator new(size_t) {
        if(!recycle.empty()) {
            Node* tmp=(Node*)recycle.back();
            recycle.pop_back();
            if(tmp->ch[0]) recycle.push_back(tmp->ch[0]);
            if(tmp->ch[1]) recycle.push_back(tmp->ch[1]);
            return tmp;
        }
        static Node *mempool,*C;
        if(mempool==C) mempool=(C=new Node[1<<20])+(1<<20);
        return C++;
    }
    void operator delete(void* tmp) {
        if(tmp) recycle.push_back(tmp);
        return ;
    }

    void maintain() {
        siz=0, sum=0;
        if(ch[0]) siz+=ch[0]->siz, sum+=ch[0]->sum;
        if(ch[1]) siz+=ch[1]->siz, sum+=ch[1]->sum;
        return ;
    }
}*root[N];
int T,n,pa[N];
inline int find_pa(int x) { return pa[x]==x ? pa[x] : pa[x]=find_pa(pa[x]); }
void Insert(Node*& o,int pos,int val,int L,int R) {
    if(!o) o=new Node();
    if(L==R) {
        o->siz+=val;
        o->sum=o->siz*log(L);
        return ;
    }
    int mid=L+R>>1;
    if(pos<=mid) Insert(o->ch[0],pos,val,L,mid);
    else Insert(o->ch[1],pos,val,mid+1,R);
    o->maintain();
    return ;
}
void Merge(Node*& x,Node*& y) {
    if(!y) return ;
    if(!x) {
        x=y;
        return ;
    }
    x->siz+=y->siz, x->sum+=y->sum;
    Merge(x->ch[0],y->ch[0]), Merge(x->ch[1],y->ch[1]);
    return ;
}
void Clear(Node*& o,int l,int r,int L,int R) {
    if(l>r) return ;
    if(l==L && r==R) {
        delete(o);
        o=NULL;
        return ;
    }
    int mid=L+R>>1;
    if(r<=mid) Clear(o->ch[0],l,r,L,mid);
    else if(l>mid) Clear(o->ch[1],l,r,mid+1,R);
    else Clear(o->ch[0],l,mid,L,mid), Clear(o->ch[1],mid+1,r,mid+1,R);
    o->maintain();
    return ;
}
int Query_siz(Node* o,int l,int r,int L,int R) {
    if(l>r || !o) return 0;
    if(l==L && r==R) return o->siz;
    int mid=L+R>>1;
    if(r<=mid) return Query_siz(o->ch[0],l,r,L,mid);
    if(l>mid) return Query_siz(o->ch[1],l,r,mid+1,R);
    return Query_siz(o->ch[0],l,mid,L,mid)+Query_siz(o->ch[1],mid+1,r,mid+1,R);
}
int Query_Kth(Node* o,int x,int L,int R) {
    if(L==R) return L;
    if(!o) return -1;
    if(o->siz<x) return -1;
    int mid=L+R>>1;
    int lsiz=o->ch[0] ? o->ch[0]->siz : 0;
    if(lsiz>=x) return Query_Kth(o->ch[0],x,L,mid);
    return Query_Kth(o->ch[1],x-lsiz,mid+1,R);
}
int main() {
    for(scanf("%d",&T);T;T--) {
        int mode,x,y;
        scanf("%d",&mode);
        switch(mode) {
            case 1: {
                scanf("%d",&x);
                Insert(root[++n],x,1,1,M);
                pa[n]=n;
                break;
            }
            case 2: {
                scanf("%d%d",&x,&y);
                x=find_pa(x), y=find_pa(y);
                if(x==y) continue;
                if(root[x]->siz<root[y]->siz) swap(x,y);
                pa[y]=x;
                Merge(root[x],root[y]);
                break;
            }
            case 3: {
                scanf("%d%d",&x,&y);
                x=find_pa(x);
                int z=Query_siz(root[x],1,y-1,1,M);
                Insert(root[x],y,z,1,M);
                Clear(root[x],1,y-1,1,M);
                break;
            }
            case 4: {
                scanf("%d%d",&x,&y);
                x=find_pa(x);
                int z=Query_siz(root[x],y+1,M,1,M);
                Insert(root[x],y,z,1,M);
                Clear(root[x],y+1,M,1,M);
                break;
            }
            case 5: {
                scanf("%d%d",&x,&y);
                x=find_pa(x);
                printf("%d\n",Query_Kth(root[x],y,1,M));
                break;
            }
            case 6: {
                scanf("%d%d",&x,&y);
                x=find_pa(x), y=find_pa(y);
                printf("%d\n",root[x]->sum>root[y]->sum);
                break;
            }
            case 7: {
                scanf("%d",&x);
                x=find_pa(x);
                printf("%d\n",root[x]->siz);
                break;
            }
        }
    }
    return 0;
}

選中上方內容可看見更多內容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章