首页 > 其他分享 >[BZOJ 4399] 魔法少女LJJ

[BZOJ 4399] 魔法少女LJJ

时间:2024-12-28 17:20:04浏览次数:6  
标签:4399 cnt LJJ val int 权值 节点 BZOJ

魔法少女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;
}

标签:4399,cnt,LJJ,val,int,权值,节点,BZOJ
From: https://www.cnblogs.com/LG017/p/18637692

相关文章

  • BZOJ P4883 [Lydsy2017年5月月赛]棋盘上的守卫 做题记录
    前置芝士:kruskal求最小生成树,并查集原题链接:hydro思路我们将它建模成图论问题,相当于从\(i\)到\(j\)连一条长度为\(a_{i,j}\)的边,然后使得每个点都有一个入度,那么就是在求最小基环树森林。至于基环树森林怎么求呢?我们使用像kruskal的思想,按照边的长度的大小对边进行排......
  • [BZOJ4771] 七彩树 题解
    好题,又学两个思路。先把问题变简单一点,去掉深度限制,那么有两种做法:经典的前驱后继转化到二维数点。颜色相同的点按\(dfs\)序排序,每个点\(+1\),相邻两点\(lca-1\)。转化为区间求和。第二种相对实现简单。假如加上深度,我们可以离线问题,按深度顺序加点。要在线的话,只......
  • [BZOJ2741][FOTILE模拟赛] L 题解
    相当好的题目,虽然和我前几天出的题重了qwq。\(lmx\)是我们的红太阳,没有他我们就会死!!!暴力枚举一个端点,然后用可持久化\(01\Trie\)或者离线\(Trie\)(当然这题用不了,但不强制在线的话是可以的)得到答案。时间复杂度\(O(nm\logn)\),过不了,考虑优化。红太阳\(lmx\)曾经说过:当......
  • [BZOJ3489] A simple rmq problem
    考虑当没有强制在线时,容易想到一个点\(i\)所影响的区间\([l,r]\)满足\(pr_i<l\lei,i\ler<nx_i\)。显然可以转化为矩阵修改,单点求\(\max\)的问题。那扫描线\(+\set\)轻松拿下。强制在线就把线段树换成主席树就可以了。注意这里不能下传标记,所以得用标记永久化。但是......
  • [BZOJ3569] DZY Loves Chinese II 题解
    考虑不联通的情况。图不好做,就造一棵生成树出来,由于是无向图,所以只有树边和返祖边。发现在一条树边断开后,生成树会分成两个连通块,由覆盖这条树边的返祖边链接,只有这些返祖边也全部断开,原图才会不联通。想到异或的优良性质。我们给所有返祖边在\([0,2^{63})\)中随机一个值作为......
  • [BZOJ3811] 玛里苟斯 题解
    不得不说这题的确挺苟的。注:下述“引理”表示:对于长度为\(n\)的数组\(V\),其线性基为\(B\),定义\(c_v=\bigoplus\limits_{a\inv}a\),\(num_k=\sum\limits_{v\subseteqV}[c_v=k]\),则\(\forallk\in\mathbb{N},num_k\in\{0,2^{n-|B|}\}\)。对于\(k=1\)的情况,容易想到按......
  • Becoder # 16288. 「BZOJ2288 POJ Challenge」生日礼物
    题目链接:BecoderorLuogu首先我们可以先把点给缩一缩,把连续的正数点和连续的负数点分别缩成一个点,比如123-1-112这个东西我们就可以将其缩成6-23我们可以发现,求前者的值等于求后者的值,我们就将原序列变为了正负交替的序列。然后我们就可以开始反悔贪心,将所有数的......
  • BZOJ 4545 DQS 的 trie 题解
    Statement维护一棵树,边权\(\in\{\texttta,\textttb,\textttc\}\),根为\(1\),定义这棵树的子串为从\(1\)走到所有点构成的字符串的所有后缀,需要支持以下操作:问当前树的本质不同子串数给一个点添加一棵子树问一个串在当前树中作为子串的出现次数Solution直接广义SAM+......
  • BZOJ4144 Petrol
    最小生成树+最短路+并查集维护题目#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=2e5+100,M=N*2;intn,m,s;inth[N],e[M],ne[M],w[M],idx;intdis[N],pos[N];boolvis[N];intf[N];inta[N]; boolans[N];intq;structNODE{......
  • BZOJ 3796 Mushroom追妹纸 题解
    Statement给\(s_1,s_2,s_3\),求最长的\(w\)的长度,满足\(w\)是\(s_1\)子串\(w\)是\(s_2\)子串\(s_3\)不是\(w\)子串Solution1以下是我没看题解瞎胡的首先一个弱智想法是,枚举\(s_1\)上\(w\)的左端点,二分右端点,判定时\(s_2\)用SAM,\(s_3\)用单串AC自动......