题意

https://www.lydsy.com/JudgeOnline/problem.php?id=4399

思路

码农题,需要一定代码功底。方法很暴力,先将权值离散,表示在线段树里储存的位置,每个连通块用一棵动点线段树存储,合并两个连通块直接对两个动点线段树进行合并,查询操作在当前连通块的线段树上进行,只不过有询问乘积大小,直接权值取原权值的 \(\ln​\) ,比较和的大小即可。

现在分析线段树合并的复杂度,举一个最基本的例子:权值为\([1,n]\) ,\(n\) 棵动点线段树,每个线段树插入了一个权值,那么总共有 \(n\log n\) 个点,而每一次合并相当于少掉了一个点,那么合并完这 \(n\) 棵线段树后复杂度就是消失的点的个数,不会超过总共的点数,所以复杂度是 \(n \log n\) 的。

类似的,对最一般的情况,也是一样的分析方法,最后得出线段树合并的复杂度为节点个数的结论。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=4e5+5;
const int NN=N*12;struct SegmentTree
{struct node{int cnt;double sum;node operator +(const node &_)const{return (node){cnt+_.cnt,sum+_.sum};}};node nd[NN];int lson[NN],rson[NN],rt[N],tot;int &operator [](const int x){return rt[x];}void build(){memset(rt,0,sizeof(rt));nd[tot=0]=(node){0,0};lson[0]=rson[0]=0;}void create(int &k){if(!k)k=++tot,nd[k]=nd[0],lson[k]=rson[k]=0;}void update(int &k,int x,int addcnt,double addsum,int l,int r){create(k);if(l==r){nd[k].cnt+=addcnt;nd[k].sum+=addsum;return;}int mid=(l+r)>>1;if(x<=mid)update(lson[k],x,addcnt,addsum,l,mid);else update(rson[k],x,addcnt,addsum,mid+1,r);nd[k]=nd[lson[k]]+nd[rson[k]];}int sweep_off(int &k,int L,int R,int l,int r){if(!k)return 0;if(L<=l&&r<=R){int res=nd[k].cnt;k=0;return res;}int mid=(l+r)>>1,res=0;if(L<=mid)res+=sweep_off(lson[k],L,R,l,mid);if(R>mid)res+=sweep_off(rson[k],L,R,mid+1,r);nd[k]=nd[lson[k]]+nd[rson[k]];return res;}int querycnt(int k){return nd[k].cnt;}double querysum(int k){return nd[k].sum;}int queryKth(int k,int K,int l,int r){if(l==r)return l;int mid=(l+r)>>1;if(nd[lson[k]].cnt>=K)return queryKth(lson[k],K,l,mid);else return queryKth(rson[k],K-nd[lson[k]].cnt,mid+1,r);}void merge(int &x,int y,int l,int r){if(!x||!y){x=(x|y);return;}if(l==r){nd[x]=nd[x]+nd[y];return;}int mid=(l+r)>>1;merge(lson[x],lson[y],l,mid);merge(rson[x],rson[y],mid+1,r);nd[x]=nd[lson[x]]+nd[rson[x]];}
}ST;
int n,m,fa[N];
int op[N],a[N],b[N];
int disc[N],tot;
double logdisc[N];
int getfa(int k){return k==fa[k]?k:fa[k]=getfa(fa[k]);}int main()
{scanf("%d",&m);FOR(i,1,m){scanf("%d%d",&op[i],&a[i]);if(op[i]!=1&&op[i]!=7)scanf("%d",&b[i]);}FOR(i,1,m){if(op[i]==1)disc[++tot]=a[i];else if(op[i]==3||op[i]==4)disc[++tot]=b[i];}sort(disc+1,disc+1+tot);tot=unique(disc+1,disc+1+tot)-disc-1;FOR(i,1,m){if(op[i]==1)a[i]=lower_bound(disc+1,disc+1+tot,a[i])-disc;else if(op[i]==3||op[i]==4)b[i]=lower_bound(disc+1,disc+1+tot,b[i])-disc;}FOR(i,1,tot)logdisc[i]=log(disc[i]);ST.build();FOR(i,1,m){if(op[i]==1){n++;fa[n]=n;ST.update(ST[n],a[i],1,logdisc[a[i]],1,tot);}else if(op[i]==2){a[i]=getfa(a[i]),b[i]=getfa(b[i]);if(a[i]==b[i])continue;ST.merge(ST[a[i]],ST[b[i]],1,tot);fa[b[i]]=a[i];}else if(op[i]==3){if(b[i]==1)continue;a[i]=getfa(a[i]);int cnt=ST.sweep_off(ST[a[i]],1,b[i]-1,1,tot);ST.update(ST[a[i]],b[i],cnt,cnt*logdisc[b[i]],1,tot);}else if(op[i]==4){if(b[i]==tot)continue;a[i]=getfa(a[i]);int cnt=ST.sweep_off(ST[a[i]],b[i]+1,tot,1,tot);ST.update(ST[a[i]],b[i],cnt,cnt*logdisc[b[i]],1,tot);}else if(op[i]==5){a[i]=getfa(a[i]);printf("%d\n",disc[ST.queryKth(ST[a[i]],b[i],1,tot)]);}else if(op[i]==6){a[i]=getfa(a[i]),b[i]=getfa(b[i]);if(ST.querysum(ST[a[i]])>ST.querysum(ST[b[i]]))puts("1");else puts("0");}else if(op[i]==7){a[i]=getfa(a[i]);printf("%d\n",ST.querycnt(ST[a[i]]));}}return 0;
}

转载于:https://www.cnblogs.com/Paulliant/p/10159208.html

BZOJ 4399 魔法少女LJJ(线段树合并)相关推荐

  1. BZOJ 4399: 魔法少女LJJ 线段树合并 + 对数

    Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅 ...

  2. BZOJ4399魔法少女LJJ——线段树合并+并查集

    题目描述 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了 LJJ感叹道"这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉 ...

  3. bzoj4399 魔法少女LJJ 线段树合并

    只看题面绝对做不出系列.... 注意到\(c \leqslant 7\),因此不会有删边操作(那样例删边干嘛) 注意到\(2, 5\)操作十分的有趣,启示我们拿线段树合并来做 操作\(7\)很好处理 ...

  4. [BZOJ4399]魔法少女LJJ(线段树合并)

    请仔细阅读数据范围,c<=7. 线段树合并裸题,对于乘积大小比较,使用log即可. 1 #include<cmath> 2 #include<cstdio> 3 #inc ...

  5. bzoj 4399 魔法少女LJJ

    4399: 魔法少女LJJ Time Limit: 20 Sec  Memory Limit: 162 MB http://www.lydsy.com/JudgeOnline/problem.php? ...

  6. BZOJ 4399: 魔法少女LJJ

    4399: 魔法少女LJJ Time Limit: 20 Sec Memory Limit: 162 MB Submit: 287 Solved: 73 Description 在森林中见过会动的树, ...

  7. 魔法少女 LJJ——线段树

    题目 [题目描述] 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女 LJJ 已经觉得自己见过世界上的所有稀奇古怪的事情了. LJJ 感叹道"这里真是个迷人的绿色世界,空气清新. ...

  8. BZOJ.2212.[POI2011]Tree Rotations(线段树合并)

    题目链接 \(Description\) 给定一棵n个叶子的二叉树,每个叶节点有权值(1<=ai<=n).可以任意的交换两棵子树.问最后顺序遍历树得到的叶子权值序列中,最少的逆序对数是多少 ...

  9. BZOJ.4552.[HEOI2016/TJOI2016]排序(线段树合并/二分 线段树)

    题目链接 对于序列上每一段连续区间的数我们都可以动态开点建一棵值域线段树.初始时就是\(n\)棵. 对于每次操作,我们可以将\([l,r]\)的数分别从之前它所属的若干段区间中分离出来,合并. 对于升 ...

  10. BZOJ 3910 并查集+线段树合并

    思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...

最新文章

  1. linux单 网卡添加多个网段的ip,[转载]linux 单网卡来绑定多IP实现多网段访问以及多网卡绑定单IP实现附载均...
  2. AngularDart Material Design 卡片
  3. C++应用程序性能优化(三)——C++语言特性性能分析
  4. python花钱培训值吗-交钱了,学了3天Python编程,我想放弃了......
  5. JDBC-Statement 对象
  6. PHP进行生成并且导出CSV文件
  7. Python 序列与映射的解包操作
  8. 怎么提高python能力_怎样提高python分析数据能力?
  9. 清华大学计算机系牛人,高考状元不靠加分靠实力
  10. pecamaker+corosync高可用集群的搭建
  11. Arbin数据导出---cellpy库的安装与使用
  12. myeclipse2014 mysql连接池_MyEclipse配置数据源连接池
  13. UDT中的epoll
  14. linux内核IO模块plug/unplug机制
  15. 【预测模型】基于matlab GUI BP神经网络+最小二乘法预测模型【含Matlab源码 208期】
  16. java 截取掉数字前面的0_java 保留字符串数字的位数,不够前面补0
  17. sql数据库可以创建同义词_如何使用同义词简化SQL Server数据库对象的使用
  18. 爱快路由器接水星交换机-划分vlan
  19. mysql下载64位 太平洋,Win10 64位安装MySQL5.6.35的详细教程
  20. centos7下搭建nextcloud云(使用阿里云轻量服务器+oss对象储存)

热门文章

  1. 阿里云服务器价格,最新收费标准报价及活动价格表
  2. 小码哥教育笔记之VueDay01课程回顾
  3. 网络安全涉及到的知识积累(1)
  4. [pip安装]There was a problem confirming the ssl certificate
  5. 原型工具——墨刀以及Axure的比较
  6. Codeforces 417D.Cunning Gena (状压DP)
  7. linux strace php,在Linux下使用strace窥视Oracle LGWR进程
  8. 论文《Are We Really Making Much Progress? A Worrying Analysis of Recent Neural Recommendation ...》阅读
  9. 1、蛋白质二级结构预测方法
  10. 零基础如何学 Web 前端开发