zoukankan      html  css  js  c++  java
  • BZOJ4399魔法少女LJJ——线段树合并+并查集

    题目描述

    在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女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很郁闷,你能帮帮他吗

    输入

    第一行有一个正整数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点的所有连边
    具体输出格式见样例

    输出

    样例输入

    11
    1 2
    1 3
    1 4
    1 5
    1 6
    2 1 2
    2 2 3
    2 3 4
    2 4 5
    3 2 5
    5 3 4

    样例输出

    5

    提示

    对100%的数据 0<=m<=400000,c<=7,所有出现的数均<=1000000000,所有出现的点保证存在

    【HINT】请认真阅读题面

    刚读完题面可能会觉得这道题不可做,8、9操作怎么搞?但再往下看看数据范围c<=7,根本不存在后两个操作!

    所以原题样例也就修改成了上面的这个样例。这样用线段树合并+并查集就能做了。

    我们来分别说说每个操作:

    1、直接建一个点,并建一棵这个点所代表的权值线段树(别忘了动态开点哦!)

    2、如果这两个点在同一棵联通块中这个操作就没用了,因为询问只询问联通块信息,否则把这两个点所在的联通块合并,并把两个联通块的祖先所代表的权值线段树合并

    3、直接找到a联通块祖先的线段树,区间修改就好了,具体见代码。

    4、实现同上。

    5、还是找到联通块祖先的权值线段树查询第k小。

    6、正常思路是维护线段树区间乘积,然后直接查询a,b联通块祖先线段树中根节点的权值乘积就好了,但发现乘积太大了,因此考虑转成log。因为log(x*y)=logx+logy,所以每个点权值取log然后维护区间和即可,精度在double下能过。

    7、如果用启发式合并直接输出联通块大小即可,不启发式合并还要在线段树上维护区间数的个数。

    #include<set>
    #include<map>
    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<vector>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int f[400010];
    int root[400010];
    int cnt;
    int size[400010];
    int ls[7600010];
    int rs[7600010];
    bool a[7600010];
    double g[7600010];
    int sum[7600010];
    int n;
    int opt;
    int x,y;
    int num;
    int find(int x)
    {
        if(f[x]==x)
        {
            return x;
        }
        return f[x]=find(f[x]);
    }
    void pushup(int rt)
    {
        sum[rt]=sum[ls[rt]]+sum[rs[rt]];
        g[rt]=g[ls[rt]]+g[rs[rt]];
    }
    void pushdown(int rt)
    {
        if(a[rt])
        {
            a[ls[rt]]=1;
            a[rs[rt]]=1;
            sum[ls[rt]]=0;
            g[ls[rt]]=0;
            sum[rs[rt]]=0;
            g[rs[rt]]=0;
            a[rt]=0;
        }
    }
    void insert(int &rt,int l,int r,int k)
    {
        if(!rt)
        {
            rt=++cnt;
        }
        if(l==r)
        {
            sum[rt]++;
            g[rt]+=log(l);
            return ;
        }
        int mid=(l+r)>>1;
        if(k<=mid)
        {
            insert(ls[rt],l,mid,k);
        }
        else
        {
            insert(rs[rt],mid+1,r,k);
        }
        pushup(rt);
    }
    void changemin(int &rt,int l,int r,int k,int x)
    {
        if(!rt)
        {
            rt=++cnt;
        }
        if(l==r)
        {
            sum[rt]+=x;
            g[rt]+=log(l)*x;
            return ;
        }
        int mid=(l+r)>>1;
        pushdown(rt);
        if(k<=mid)
        {
            changemin(ls[rt],l,mid,k,x);
        }
        else
        {
            x+=sum[ls[rt]];;
            g[ls[rt]]=0;
            sum[ls[rt]]=0;
            a[ls[rt]]=1;
            changemin(rs[rt],mid+1,r,k,x);
        }
        pushup(rt);
    }
    void changemax(int &rt,int l,int r,int k,int x)
    {
        if(!rt)
        {
            rt=++cnt;
        }
        if(l==r)
        {
            sum[rt]+=x;
            g[rt]+=log(l)*x;
            return ;
        }
        int mid=(l+r)>>1;
        pushdown(rt);
        if(k<=mid)
        {
            x+=sum[rs[rt]];
            sum[rs[rt]]=0;
            g[rs[rt]]=0;
            a[rs[rt]]=1;
            changemax(ls[rt],l,mid,k,x);
        }
        else
        {
            changemax(rs[rt],mid+1,r,k,x);
        }
        pushup(rt);
    }
    int query(int rt,int l,int r,int k)
    {
        if(l==r)
        {
            return l;
        }
        int mid=(l+r)>>1;
        pushdown(rt);
        if(sum[ls[rt]]>=k)
        {
            return query(ls[rt],l,mid,k);
        }
        else
        {
            return query(rs[rt],mid+1,r,k-sum[ls[rt]]);
        }
    }
    void merge(int &rt,int x)
    {
        if(!rt||!x)
        {
            rt=rt+x;
            return ;
        }
        pushdown(rt);
        pushdown(x);
        sum[rt]+=sum[x];
        g[rt]+=g[x];
        merge(ls[rt],ls[x]);
        merge(rs[rt],rs[x]);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&opt);
            if(opt==1)
            {
                scanf("%d",&x);
                num++;
                f[num]=num;
                size[num]=1;
                insert(root[num],1,1000000000,x);
            }
            else if(opt==2)
            {
                scanf("%d%d",&x,&y);
                int fx=find(x);
                int fy=find(y);
                if(fx!=fy)
                {
                    if(size[fx]>size[fy])
                    {
                        size[fx]+=size[fy];
                        f[fy]=fx;
                        merge(root[fx],root[fy]);
                    }
                    else
                    {
                        size[fy]+=size[fx];
                        f[fx]=fy;
                        merge(root[fy],root[fx]);
                    }
                }
            }
            else if(opt==3)
            {
                scanf("%d%d",&x,&y);
                x=find(x);
                changemin(root[x],1,1000000000,y,0);
            }
            else if(opt==4)
            {
                scanf("%d%d",&x,&y);
                x=find(x);
                changemax(root[x],1,1000000000,y,0);
            }
            else if(opt==5)
            {
                scanf("%d%d",&x,&y);
                x=find(x);
                printf("%d
    ",query(root[x],1,1000000000,y));
            }
            else if(opt==6)
            {
                scanf("%d%d",&x,&y);
                x=find(x);
                y=find(y);
                if(g[root[x]]>g[root[y]])
                {
                    printf("1
    ");
                }
                else
                {
                    printf("0
    ");
                }
            }
            else if(opt==7)
            {
                scanf("%d",&x);
                x=find(x);
                printf("%d
    ",size[x]);
            }
        }
    }
  • 相关阅读:
    javascript动态创建Option选项
    Javascript中最常用的25个经典技巧
    C#常用函数和方法集
    C#邮件发送程序
    CSS菜单
    笔记本将有线变无线网
    svn有权限但是不能提交的原因
    IE6在https下认为iframe和about:blank不安全
    VS2008创建MFC项目提示无法找到userimages.bmp
    往数据库中插入流数据的问题
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9740692.html
Copyright © 2011-2022 走看看