• 直接维护乘积是肯定不可行的, 精度会爆炸, 于是我们来维护对数的和, 最后来计算最高位即可
  • 那么转换成区间求和, 区间排序
  • 区间排序的方式可以采用线段树维护最大递增块来解决,外层用set来维护线段树的区间, 然后利用线段树的合并分裂性质来操作即可
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<iostream>
#include<set>
#include<cmath>
#define ll long long
#define M (1 << 18)
#define N 20000010
#define double long double
const double eps = 1e-8;
using namespace std;
int read() {
int nm = 0, f = 1;
char c = getchar();
for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
return nm * f;
}
double c[M], ver[M];
int num[M], n, m;
int lowbit(int x) {
return x & -x;
}
void add(int x, double v) {
for(int i = x; i <= n; i += lowbit(i)) c[i] += v;
} double query(int x) {
double ans = 0;
for(int i = x; i; i -= lowbit(i)) ans += c[i];
return ans;
} struct Note {
int l, r, rt, op;
Note(int ln = 0, int rn = 0, int rtn = 0, int opn = 0) {
l = ln, r = rn, rt = rtn, op = opn;
}
bool operator < (const Note &b) const {
return this->l < b.l;
}
};
#define S set<Note>::iterator
set<Note> st;
int ls[N], rs[N], cnt[N], f;
double sum[N]; void pushup(int now) {
cnt[now] = cnt[ls[now]] + cnt[rs[now]];
sum[now] = sum[ls[now]] + sum[rs[now]];
} 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]);
cnt[x] = cnt[x] + cnt[y];
sum[x] = sum[x] + sum[y];
return x;
} S insert(Note x) {
add(x.l, sum[x.rt]);
return st.insert(x).first;
} void Del(S it) {
add(it->l, -sum[it->rt]);
st.erase(it);
} void split(int x, int &rt1, int &rt2, int l, int r, int k) {
rt1 = ++f;
rt2 = ++f;
if(l == r) {
cnt[rt1] = k;
sum[rt1] = ver[l] * k;
cnt[rt2] = cnt[x] - cnt[rt1];
sum[rt2] = sum[x] - sum[rt1];
return;
}
int mid = (l + r) >> 1;
if(cnt[ls[x]] >= k) {
rs[rt2] = rs[x];
split(ls[x], ls[rt1], ls[rt2], l, mid, k);
} else {
ls[rt1] = ls[x];
split(rs[x], rs[rt1], rs[rt2], mid + 1, r, k - cnt[ls[x]]);
}
pushup(rt1);
pushup(rt2);
} S split(int x) {
if(x > n) return st.end();
S it = st.upper_bound(Note(x, 0, 0, 0));
it--;
Note hh = *it;
if(hh.l == x) return it;
int rt1, rt2;
if(!hh.op) split(hh.rt, rt1, rt2, 1, n, x - hh.l);
else split(hh.rt, rt2, rt1, 1, n, hh.r - x + 1);
Del(it);
insert(Note(hh.l, x - 1, rt1, hh.op));
return insert(Note(x, hh.r, rt2, hh.op));
} void build(int &x, int l, int r, int k) {
x = ++f;
cnt[x]++;
sum[x] += ver[k];
if(l == r) return;
int mid = (l + r) >> 1;
if(k <= mid) build(ls[x], l, mid, k);
else build(rs[x], mid + 1, r, k);
} int calc(int l, int r) {
S L = split(l), R = split(r + 1);
R--;
double ans = query(R->r) - query(L->l - 1);
double out = pow(10, ans - floorl(ans) + eps);
return floorl(out);
} void updata(int l, int r, int op) {
S L = split(l);
split(r + 1);
int rt = 0;
for(S it = L; it != st.end() && (it->l) <= r; Del(it++)) {
rt = merge(rt, it->rt);
}
insert(Note(l, r, rt, op));
} int main() {
n = read(), m = read();
for(int i = 1; i <= n; i++) num[i] = read(), ver[i] = log10(i);
for(int i = 1; i <= n; i++) {
int now;
build(now, 1, n, num[i]);
insert(Note(i, i, now, 0));
}
while(m--) {
int op = read(), l = read(), r = read();
if(op == 2) cout << calc(l, r) << "\n";
else {
op = read() ^ 1;
updata(l, r, op);
}
}
return 0;
}

Philosopher(set 线段树合并)的更多相关文章

  1. 【xsy2194】Philosopher set+线段树合并

    题目大意:给你一个长度为$n$的序列,有$m$次操作,每次操作是以下两种之一: 对某个区间内的数按照升序/降序排序,询问某个区间内数的积在十进制下首位数字是多少. 数据范围:$n,m≤2\times ...

  2. [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】

    题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动 ...

  3. [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】

    题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换 ...

  4. BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )

    路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, ...

  5. BZOJ2733 [HNOI2012]永无乡 【线段树合并】

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  6. bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)

    [bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...

  7. bzoj3702二叉树 线段树合并

    3702: 二叉树 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 600  Solved: 272[Submit][Status][Discuss] ...

  8. BZOJ_2212_[Poi2011]Tree Rotations_线段树合并

    BZOJ_2212_[Poi2011]Tree Rotations_线段树合并 Description Byteasar the gardener is growing a rare tree cal ...

  9. B20J_2733_[HNOI2012]永无乡_权值线段树合并

    B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...

  10. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

随机推荐

  1. Linux学习笔记之scp远程拷贝文件

    0x00 拷贝本机/home/administrator/test整个目录至远程主机192.168.1.100的/root目录下 代码如下: scp -r /home/administrator/te ...

  2. OpenJDK下SpringBoot使用HttpSession时页面打开卡住

    近期将一个老项目向ARM版的CentOS7移植时,遇到了SpringBoot启动顺利,但访问页面卡住的问题.由于是aarch64架构,因此使用了openjdk,这个项目之前在x86_64环境下一直是用 ...

  3. Python传入参数的几种方法

    写在前面 Python唯一支持的参数传递方式是『共享传参』(call by sharing) 多数面向对象语言都采用这一模式,包括Ruby.Smalltalk和Java(Java的引用类型是这样,基本 ...

  4. tf.where()函数的解析

    tf.where()的使用,该函数会返回满足条件的索引.经验证,发现返回均是二维矩阵,可以说明该函数用二维矩阵给出满足条件的位置索引.(若有错误,欢迎指正.) 代码如下:import tensorfl ...

  5. 探究java对象头

    探究java对象头 研究java对象头,我这里先截取Hotspot中关于对象头的描述,本文研究基于64-bit HotSpot VM 文件路径 openjdk-jdk8u-jdk8u\hotspot\ ...

  6. xshell使用zmodem拖拽上传

    一.目的 windows向centos_linux服务器上传文件可以用ftp上传,但是没zmodem方便,zmodem拖拽上传,可以上传到指定的目录下. 二.安装使用 执行下面的命令安装后就可以使用了 ...

  7. ssh-agent的作用

    明明在github上配置了ssh公钥,拉代码时却报错: sign_and_send_pubkey: signing failed: agent refused operation 解决方法:在~/.z ...

  8. 深入浅出《设计模式》之简单工厂模式(C++)

    前言 模式介绍 简单工厂模式其实并不属于GoF23(23种设计模式),更类似工厂模式的一种变型.其定义是可以根据参数的不同返回不同类的实例.简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实 ...

  9. SVG撑满页面

    当viewBox属性固定,默认修改svg标签的宽高,svg都会按比例缩放 我们现在不想按比例缩放,需要svg撑满整个画面 这里只需为svg标签添加一个关键属性:preserveAspectRatio ...

  10. Android培训准备资料之五大布局简单介绍

    本篇博客主要简单的给大家介绍一下Android五大布局 (1)LinearLayout(线性布局) (2)RelativeLayout(相对布局) (3)FrameLayout(帧布局) (4)Abs ...