只看题面绝对做不出系列....


注意到\(c \leqslant 7\),因此不会有删边操作(那样例删边干嘛)

注意到\(2, 5\)操作十分的有趣,启示我们拿线段树合并来做

操作\(7\)很好处理

操作\(6\),维护对数的和即可

操作\(3, 4\),乍看不好处理,然而势能分析一下就可以得出暴力的复杂度是\(O(n \log n)\)的

然而我好像写了个稳定的\(\log\)维护

然后好像就没了诶......

空间直接动态开点是开不下的....

需要预先离散化权值

复杂度\(O(n \log n)\)


#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; #define de double
#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++) #define gc getchar
inline int read() {
int p = 0, w = 1; char c = gc();
while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
return p * w;
} const int sid = 5e5 + 5;
const int eid = 5e6 + 5; de mul[eid];
int n, m, id, nc;
int rt[sid], fa[sid];
int ls[eid], rs[eid], sz[eid];
int opt[sid], c1[sid], c2[sid], T[sid]; inline int find(int o) { return fa[o] = (o == fa[o]) ? o : find(fa[o]); } inline void upd(int o) {
int lc = ls[o], rc = rs[o];
sz[o] = sz[lc] + sz[rc];
mul[o] = mul[lc] + mul[rc];
} inline int merge(int x, int y) {
if(!x || !y) return x + y;
ls[x] = merge(ls[x], ls[y]);
rs[x] = merge(rs[x], rs[y]);
sz[x] = sz[x] + sz[y];
mul[x] = mul[x] + mul[y];
return x;
} inline void mdf(int &o, int l, int r, int c, int v) {
if(!o) o = ++ id;
if(l == r) { sz[o] = v; mul[o] = (de)v * (de)log(T[c]); return; }
int mid = (l + r) >> 1;
if(c <= mid) mdf(ls[o], l, mid, c, v);
else mdf(rs[o], mid + 1, r, c, v);
upd(o);
} inline int dfs(int &o, int l, int r, int ml, int mr) {
if(!o || ml > r || mr < l) return 0;
if(ml <= l && mr >= r) {
int tmp = sz[o]; o = 0;
return tmp;
}
int mid = (l + r) >> 1;
int ret = dfs(ls[o], l, mid, ml, mr) + dfs(rs[o], mid + 1, r, ml, mr);
upd(o); return ret;
} inline int qry(int o, int l, int r, int k) {
if(l == r) return T[l];
int mid = (l + r) >> 1;
if(sz[ls[o]] >= k) return qry(ls[o], l, mid, k);
else return qry(rs[o], mid + 1, r, k - sz[ls[o]]);
} void calc() {
rep(i, 1, m) {
opt[i] = read(); c1[i] = read();
if(opt[i] != 1 && opt[i] != 7) c2[i] = read();
if(opt[i] == 1) T[++ nc] = c1[i];
if(opt[i] == 3 || opt[i] == 4) T[++ nc] = c2[i];
} sort(T + 1, T + nc + 1);
nc = unique(T + 1, T + nc + 1) - T - 1;
rep(i, 1, m) {
if(opt[i] == 1)
c1[i] = lower_bound(T + 1, T + nc + 1, c1[i]) - T;
if(opt[i] == 3 || opt[i] == 4)
c2[i] = lower_bound(T + 1, T + nc + 1, c2[i]) - T;
} rep(i, 1, m) {
int u, v, w, num;
switch(opt[i]) {
case 1 :
n ++; fa[n] = n;
mdf(rt[n], 1, nc, c1[i], 1); break;
case 2 :
u = find(c1[i]); v = find(c2[i]);
if(u == v) break;
fa[v] = u; rt[u] = merge(rt[u], rt[v]); break;
case 3 :
u = find(c1[i]); w = c2[i];
num = dfs(rt[u], 1, nc, 1, w);
mdf(rt[u], 1, nc, w, num); break;
case 4 :
u = find(c1[i]); w = c2[i];
num = dfs(rt[u], 1, nc, w, nc);
mdf(rt[u], 1, nc, w, num); break;
case 5 :
u = find(c1[i]); w = c2[i];
printf("%d\n", qry(rt[u], 1, nc, w)); break;
case 6 :
u = find(c1[i]); v = find(c2[i]);
if(mul[rt[u]] > mul[rt[v]]) puts("1");
else puts("0"); break;
case 7 :
u = find(c1[i]);
printf("%d\n", sz[rt[u]]); break;
default : break;
}
}
} int main() {
//freopen("4399.in", "r", stdin);
//freopen("4399.out", "w", stdout);
m = read();
calc();
return 0;
}

bzoj4399 魔法少女LJJ 线段树合并的更多相关文章

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

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

  2. bzoj4399 魔法少女LJJ 线段树合并+线段树二分+并查集

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4399 题解 毒瘤题 \(9\) 种操作还有支持动态图的连通性 仔细读题 $ c<=7$. ...

  3. 【BZOJ4399】魔法少女LJJ 线段树合并

    [BZOJ4399]魔法少女LJJ Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的 ...

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

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

  5. BZOJ.4399.魔法少女LJJ(线段树合并)

    BZOJ 注意\(c\leq7\)→_→ 然后就是裸的权值线段树+线段树合并了. 对于取\(\max/\min\)操作可以直接区间修改清空超出范围的值,然后更新到对应位置上就行了(比如对\(v\)取\ ...

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

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

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

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

  8. BZOJ4399 魔法少女LJJ【线段树合并】【并查集】

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

  9. BZOJ4399 魔法少女LJJ(线段树合并)

    注意到只有增加点/合并的操作.这些操作都可以用线段树完成,于是线段树合并一发就好了.注意乘积大小直接比较肯定会炸,取个对数即可.数据中存在重边. #include<iostream> #i ...

随机推荐

  1. 如何编写 Typescript 声明文件

    使用TypeScript已经有了一段时间,这的确是一个好东西,虽说在使用的过程中也发现了一些bug,不过都是些小问题,所以整体体验还是很不错的. TypeScript之所以叫Type,和它的强类型是分 ...

  2. 支付宝hr终面,忐忑的等待结果

    上周一,内推网投了支付宝上海的 高级java软件开发工程师:阿里效率就是高,不到30分钟电话就过来了!约的上周五14:00面试:上周五技术面了2轮,第一轮是主管面试,貌似给了p6;第二轮部门总监面试, ...

  3. 10 Useeful Tips for Writing Effective Bash Scripts in Linux

    1.Always Use Comments in Scripts2.Make a Scripts exit When Fails    Sometimes bash may continue to e ...

  4. 【算法学习】Fhq-Treap(无旋Treap)

    Treap——大名鼎鼎的随机二叉查找树,以优异的性能和简单的实现在OIer们中广泛流传. 这篇blog介绍一种不需要旋转操作来维护的Treap,即无旋Treap,也称Fhq-Treap. 它的巧妙之处 ...

  5. 如何使用vs2012单步调试uGUI(unity3d 5.3f4)

    下载uGUI源代码 uGUI源代码地址:https://bitbucket.org/Unity-Technologies/ui 下载代码工具:tortoisehg-3.6.2-x64.msi http ...

  6. jQuery-对标签的样式操作

    一.操作样式类 // 1.给标签添加样式类 $("选择器").addClass("类名") // 2.移除标签的样式类 $("选择器").r ...

  7. 数据库-mysql触发器

    MySQL包含对触发器的支持.触发器是一种与表操作有关的数据库对象,当触发器所在表上出现指定事件时,将调用该对象,即表的操作事件触发表上的触发器的执行. 一:创建触发器 在MySQL中,创建触发器语法 ...

  8. python基础-各模块文章导航

    python基础学习日志day5-各模块文章导航 python基础学习日志day5---模块使用 http://www.cnblogs.com/lixiang1013/p/6832475.html p ...

  9. No.7 selenium学习之路之Alert弹窗

    Alert弹窗 弹窗是用工具选不到的~ 切换到alert driver.switch_to_alert() 新的语法:driver.switch_to.alert 注:新的语法不需要后面加括号 打印a ...

  10. java 内部类与控制框架

    应用程序控制框架(application framework)就是设计解决某类特殊问题的一个类,或一组类,要运用某个应用程序框架,通常是继承一个类或多个类,并覆盖这些方法.在覆盖的方法中编写代码定制应 ...