BZOJ 4399: 魔法少女LJJ(线段树)

传送门

解题思路

  出题人真会玩。。操作\(2\)线段树合并,然后每棵线段树维护元素个数和。对于\(6\)这个询问,因为乘积太大,所以要用对数。时间复杂度\(O(nlogn)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
 
using namespace std;
const int N=400005;
const int M=2000005;
 
inline int rd(){
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;  
}
 
int m,tot,rt[M],F[M],num,cpy[N],cnt,a[N],u,tmp;
 
struct Query{
    int op,x,y;
}q[N];
 
struct Segment_Tree{
    double Mul[M];
    int siz[M],ls[M],rs[M];
    void update(int &x,int l,int r,int s,int k,double now){
        if(!x) x=++tot; siz[x]+=s; Mul[x]+=s*now;
        if(l==r) return; int mid=(l+r)>>1;
        if(k<=mid) update(ls[x],l,mid,s,k,now);
        else update(rs[x],mid+1,r,s,k,now);
    }   
    int merge(int x,int y,int l,int r){
        if(!x || !y) return (x|y);
        if(l==r) {siz[x]+=siz[y]; Mul[x]+=Mul[y]; return x;}
        int mid=(l+r)>>1;
        ls[x]=merge(ls[x],ls[y],l,mid);
        rs[x]=merge(rs[x],rs[y],mid+1,r);
        siz[x]=siz[ls[x]]+siz[rs[x]];
        Mul[x]=Mul[ls[x]]+Mul[rs[x]];
        return x;
    }
    void erase(int x,int l,int r,int L,int R){
        if(L>R || !siz[x]) return;
        if(l==r) {tmp+=siz[x]; siz[x]=0; Mul[x]=0; return;}
        int mid=(l+r)>>1;
        if(L<=mid) erase(ls[x],l,mid,L,R);
        if(mid<R) erase(rs[x],mid+1,r,L,R);
        siz[x]=siz[ls[x]]+siz[rs[x]];
        Mul[x]=Mul[ls[x]]+Mul[rs[x]];
    }
    int kth(int x,int l,int r,int k){
        if(l==r) return l; int mid=(l+r)>>1;
        if(siz[ls[x]]>=k) return kth(ls[x],l,mid,k);
        else {k-=siz[ls[x]]; return kth(rs[x],mid+1,r,k);}
    }
}tree;
 
int get(int x){
    if(x==F[x]) return x;
    return F[x]=get(F[x]);
}   
 
int main(){
    m=rd(); int x,y,uu,vv;
    for(int i=1;i<=m;i++){
        q[i].op=rd(),q[i].x=rd();
        if(q[i].op==1) cpy[++cnt]=q[i].x;
        if(q[i].op==1 || q[i].op==7) continue; q[i].y=rd();
        if(q[i].op==3 || q[i].op==4) cpy[++cnt]=q[i].y;
    }
    sort(cpy+1,cpy+1+cnt); u=unique(cpy+1,cpy+1+cnt)-cpy-1;
    for(int i=1;i<=m;i++){
        if(q[i].op==1){
            x=lower_bound(cpy+1,cpy+1+u,q[i].x)-cpy;
            num++; F[num]=num; tree.update(rt[num],1,u,1,x,log(q[i].x));
        }
        else if(q[i].op==2){
            x=q[i].x,y=q[i].y; uu=get(x),vv=get(y);
            if(uu==vv) continue; F[vv]=uu;
            rt[uu]=tree.merge(rt[uu],rt[vv],1,u);
        }
        else if(q[i].op==3){
            x=q[i].x,y=lower_bound(cpy+1,cpy+1+u,q[i].y)-cpy;
            tmp=0; x=get(x); tree.erase(rt[x],1,u,1,y-1);
            if(tmp) tree.update(rt[x],1,u,tmp,y,log(q[i].y));
        }   
        else if(q[i].op==4){
            x=q[i].x,y=lower_bound(cpy+1,cpy+1+u,q[i].y)-cpy;   
            tmp=0; x=get(x); tree.erase(rt[x],1,u,y+1,u);
            if(tmp) tree.update(rt[x],1,u,tmp,y,log(q[i].y));
        }
        else if(q[i].op==5){
            x=q[i].x; y=q[i].y; x=get(x);
            printf("%d\n",cpy[tree.kth(rt[x],1,u,y)]);  
        }
        else if(q[i].op==6) {
            x=get(q[i].x); y=get(q[i].y);
            puts(tree.Mul[rt[x]]>tree.Mul[rt[y]]?"1":"0");   
        }
        else if(q[i].op==7) printf("%d\n",tree.siz[rt[get(q[i].x)]]);
    }
    return 0;
}
posted @ 2019-02-08 18:13  Monster_Qi  阅读(273)  评论(0编辑  收藏  举报