[BZOJ 4399] 魔法少女LJJ

魔法少女LJJ

Description :

题目描述
在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了

LJJ感叹道“这里真是个迷人的绿色世界,空气清新、淡雅,到处散发着醉人的奶浆味;小猴在枝头悠来荡去,好不自在;各式各样的鲜花争相开放,各种树枝的枝头挂满沉甸甸的野果;鸟儿的歌声婉转动听,小河里飘着落下的花瓣真是人间仙境”

SHY觉得LJJ还是太naive,一天,SHY带着自己心爱的图找到LJJ,对LJJ说:“既然你已经见识过动态树,动态仙人掌了,那么今天就来见识一下动态图吧”

LJJ:“要支持什么操作?”

SHY:“

1.新建一个节点,权值为x。

2.连接两个节点。

3.将一个节点a所属于的联通快内权值小于x的所有节点权值变成x。

4.将一个节点a所属于的联通快内权值大于x的所有节点权值变成x。

5.询问一个节点a所属于的联通块内的第k小的权值是多少。

6.询问一个节点a所属联通快内所有节点权值之积与另一个节点b所属联通快内所有节点权值之积的大小。

7.询问a所在联通快内节点的数量

8.若两个节点a,b直接相连,将这条边断开。

9.若节点a存在,将这个点删去。


LJJ:“我可以离线吗?”

SHY:“可以,每次操作是不加密的,”

LJJ:“我可以暴力吗?”

SHY:“自重”

LJJ很郁闷,你能帮帮他吗

数据范围及提示:

$ 1\le m \le 4\times 10^{5},opt \le 7$

Solution:

我们会发现后面两种恶心到令人发指的操作根本不用实现(\(opt \le 7\))。也就是说,我们只需要合并两个联通块就好了,这让我们很难不想到并查集.

我们维护一些并查集以支持连边操作,然后每个并查集上开一颗权值线段树,每次连边就将两颗树合并。但是我们会发现乘积貌似有点难维护,但是题目只要求比大小,所以我们并不需要维护乘积的真实值,维护对数就好了。

然后修改操作就在 \([1,x-1]\) 或者是 \([x+1,inf]\) 区间上打上删除标记并且记录删除了多少个数字 \(tmp\),然后在 \(x\) 节点上添加 \(tmp\) 个点就好了。

细节提示:

由于这题的删除标记是要 pushdown 的,所以我们在 merge 时一定要将 x,y 都 pushdown

然后就是不推荐使用太过先进的编译器。因为在并查集时,你的 find 函数就算没有 return ,编译器也可能帮你返回一个你最后调用的变量。例如:

int find(int x){fa[x] = fa[x]==x ? fa[x] : find(fa[x]);}

在我的编译器上是会直接返回 fa[x] 的,而不会报错。这两个致命错误导致我在本地调了 3h+
(╯°Д°)╯︵ ┻━┻

然后这题就做完了

Code:

#include<bits/stdc++.h>
const int N=4e5+5;
const int inf=1e9;
using namespace std;
int n,tot;
struct Segment_Tree{
    struct Tree{
        int ls,rs,cnt,tag;
        double val;
    }t[N*40];
    int cnt,rt[N];
    void erase(int x){t[x].cnt=0,t[x].val=0,t[x].tag=1;}
    void pushdown(int x)
    {
        if(!t[x].tag)return;
        erase(t[x].ls),erase(t[x].rs);
        t[x].tag=0;
    }
    void pushup(int x){t[x].cnt=t[t[x].ls].cnt+t[t[x].rs].cnt;t[x].val=t[t[x].ls].val+t[t[x].rs].val;}
    int merge(int x,int y,int l,int r)
    {
        if(!x||!y)return x|y;
        if(l==r){t[x].cnt+=t[y].cnt,t[x].val+=t[y].val;return x;}
        int mid=l+r>>1;
        pushdown(x);pushdown(y);
        t[x].ls=merge(t[x].ls,t[y].ls,l,mid);
        t[x].rs=merge(t[x].rs,t[y].rs,mid+1,r);
        pushup(x);
        return x;
    }
    void insert(int &x,int l,int r,int pos,int k)
    {
        x=(x ? x : ++cnt);

        if(l==r){t[x].cnt+=k;t[x].val+=1.0*k*log(pos);return;}
        int mid=l+r>>1;
        pushdown(x);
        if(pos<=mid)insert(t[x].ls,l,mid,pos,k);
        if(mid<pos) insert(t[x].rs,mid+1,r,pos,k);
        pushup(x);
    }
    void upd(int x,int l,int r,int L,int R,int &res)
    {
        if(L<=l&&r<=R)
        {
            res+=t[x].cnt;
            erase(x);
            return;
        }
        int mid=l+r>>1;
        pushdown(x);
        if(L<=mid)upd(t[x].ls,l,mid,L,R,res);
        if(mid<R) upd(t[x].rs,mid+1,r,L,R,res);
        pushup(x);
    }
    int query(int x,int l,int r,int k)
    {
        pushdown(x);
        if(l==r)return l;
        int mid=l+r>>1;
        if(k<=t[t[x].ls].cnt)return query(t[x].ls,l,mid,k);
        else return query(t[x].rs,mid+1,r,k-t[t[x].ls].cnt);
    }
}T;
int fa[N];
int find(int x){return fa[x] = fa[x]==x ? fa[x] : find(fa[x]);}
void work()
{
    cin>>n;
    for(int i=1,opt,x,y;i<=n;i++)
    {
        scanf("%d%d",&opt,&x);
        if(1<opt&&opt<7)scanf("%d",&y);
        if(opt==1)
        {
            tot++;
            fa[tot]=tot;
            T.insert(T.rt[tot],1,inf,x,1);
        }
        if(opt==2)
        {
            int u=find(x),v=find(y);
            if(u!=v)
            {
                fa[v]=u;
                T.rt[u]=T.merge(T.rt[u],T.rt[v],1,inf);
            }
        }
        if(opt==3)
        {
            int tmp=0;
            x=find(x);
            T.upd(T.rt[x],1,inf,1,y-1,tmp);
            T.insert(T.rt[x],1,inf,y,tmp);
        }
        if(opt==4)
        {
            int tmp=0;
            x=find(x);
            T.upd(T.rt[x],1,inf,y+1,inf,tmp);
            T.insert(T.rt[x],1,inf,y,tmp);
        }
        if(opt==5)
        {
            x=find(x);
            int ans=T.query(T.rt[x],1,inf,y);
            printf("%d\n",ans);
        }
        if(opt==6)
        {
            x=find(x),y=find(y);
            printf("%d\n",(T.t[T.rt[x]].val > T.t[T.rt[y]].val ? 1 : 0));
        }
        if(opt==7)
        {
            x=find(x);
            printf("%d\n",T.t[T.rt[x]].cnt);
        }
    }
}
int main()
{
    freopen("girl.in","r",stdin);freopen("girl.out","w",stdout);
    work();
    return 0;
}
posted @ 2024-12-28 17:13  liuboom  阅读(42)  评论(0)    收藏  举报