题目大意:给你一个长度为$n$的序列,有$m$次操作,每次操作是以下两种之一:

对某个区间内的数按照升序/降序排序,询问某个区间内数的积在十进制下首位数字是多少。

数据范围:$n,m≤2\times 10^5$ 序列内数字均不大于$n$。

我们先考虑下如何实现查询首位数字

我们发现如果直接乘的话精度损失实在太大,我们考虑把所有读入的数字全部转成对数,直接加起来。

设某个区间内对数和为$x$,那么该区间内数的积的首位为$\lfloor 10^{x-\lfloor x\rfloor} \rfloor$。

下面考虑如何做排序操作

我们先种一堆的线段树,满足每一棵线段树维护的是一个已经按照升序/降序排序好的区间(内层线段树存储该区间内放了值为哪些的数)

我们对某个区间进行排序的时候,我们要取出若干个线段树,满足这些线段树构成的区间恰好为需要排序的区间。

然后我们通过线段树合并将这些区间合并为一个区间即可,最后打上这个区间的升序/降序标记

然而有些线段树被我们需要操作的区间部分包含。

这种情况下就需要把这棵线段树从中间某个位置开始拆开。

考虑到一棵线段树所代表的区间内的数都是排序好的,我们可以根据升序/降序标记来拆开这棵线段树。

每一棵线段树的根我们可以开一个$set$来存储,每一棵线段树内的对数和我们可以单独打在一个树状数组上。

在查询答案的时候,我们按照上面做排序的方法,拆出若干棵线段树,然后直接在线段树上查询即可。

时间复杂度:$O(n\log^2\ n)$

 #include<bits/stdc++.h>
#define D long double
#define M (1<<18)
#define lowbit(x) (x&(-x))
#define N 20000005
#define S set<node>::iterator
#define eps (1e-8)
using namespace std; int n,m; D c[M]={}; void add(int x,D k){for(int i=x;i<=n;i+=lowbit(i)) c[i]+=k;}
D query(int x){D k=; for(int i=x;i;i-=lowbit(i)) k+=c[i]; return k;}
int num[M]={}; D val[M]={}; struct node{
int l,r,rt,op;
node(int ll=,int rr=,int RT=,int OP=){l=ll; r=rr; rt=RT; op=OP;}
friend bool operator <(node a,node b){return a.l<b.l;}
};set<node> s; int lc[N]={},rc[N]={},cnt[N]={},use=; D sum[N]={};
void pushup(int x){
cnt[x]=cnt[lc[x]]+cnt[rc[x]];
sum[x]=sum[lc[x]]+sum[rc[x]];
}
int merge(int x,int y){
if(!x||!y) return x|y;
lc[x]=merge(lc[x],lc[y]);
rc[x]=merge(rc[x],rc[y]);
cnt[x]=cnt[x]+cnt[y];
sum[x]=sum[x]+sum[y];
return x;
} S Ins(node x){add(x.l,sum[x.rt]);return s.insert(x).first;}
void Del(S it){add(it->l,-sum[it->rt]);s.erase(it);} void split(int x,int &rt1,int &rt2,int l,int r,int k){
rt1=++use; rt2=++use;
if(l==r){
cnt[rt1]=k; sum[rt1]=val[l]*k;
cnt[rt2]=cnt[x]-cnt[rt1];
sum[rt2]=sum[x]-sum[rt1];
return;
}
int mid=(l+r)>>;
if(cnt[lc[x]]>=k){
rc[rt2]=rc[x];
split(lc[x],lc[rt1],lc[rt2],l,mid,k);
}else{
lc[rt1]=lc[x];
split(rc[x],rc[rt1],rc[rt2],mid+,r,k-cnt[lc[x]]);
}
pushup(rt1); pushup(rt2);
}
S split(int x){
if(x>n) return s.end();
S it=s.upper_bound(node(x,,,)); it--;
node hh=*it; if(hh.l==x) return it;
int rt1,rt2;
if(!hh.op) split(hh.rt,rt1,rt2,,n,x-hh.l);
else split(hh.rt,rt2,rt1,,n,hh.r-x+);
Del(it);
Ins(node(hh.l,x-,rt1,hh.op));
return Ins(node(x,hh.r,rt2,hh.op));
} void updata(int l,int r,int op){
S L=split(l); split(r+); int rt=;
for(S it=L;it!=s.end()&&(it->l)<=r;Del(it++)){
rt=merge(rt,it->rt);
}
Ins(node(l,r,rt,op));
}
int calc(int l,int r){
S L=split(l),R=split(r+); R--;
D ans=query(R->r)-query(L->l-);
D out=pow(,ans-floorl(ans)+eps);
return floorl(out);
} void build(int &x,int l,int r,int k){
x=++use; cnt[x]++; sum[x]+=val[k];
if(l==r) return; int mid=(l+r)>>;
if(k<=mid) build(lc[x],l,mid,k);
else build(rc[x],mid+,r,k);
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",num+i);
for(int i=;i<=n;i++) val[i]=log10(i);
for(int i=;i<=n;i++){
int now; build(now,,n,num[i]);
Ins(node(i,i,now,));
}
while(m--){
int op,l,r; scanf("%d%d%d",&op,&l,&r);
if(op==) printf("%d\n",calc(l,r));
else{
scanf("%d",&op); op^=;
updata(l,r,op);
}
}
}

【xsy2194】Philosopher set+线段树合并的更多相关文章

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

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

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

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

  3. 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). 复杂度看起来不高, ...

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

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

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

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

  6. bzoj3702二叉树 线段树合并

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

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

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

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

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

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

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

随机推荐

  1. Conda下安装libsvm

    如何在canda下安装libsvm? 版本:Python是2.7 canda2 首先想到的是去Python官网上找libsvm的包,结果并没有. 这是因为libsvm是c语言编写的并不是一个Pytho ...

  2. 2018.12.31 bzoj4001: [TJOI2015]概率论(生成函数)

    传送门 生成函数好题. 题意简述:求nnn个点的树的叶子数期望值. 思路: 考虑fnf_nfn​表示nnn个节点的树的数量. 所以有递推式f0=1,fn=∑i=0n−1fifn−1−i(n>0) ...

  3. ACM-ICPC 2018 徐州赛区网络预赛 C Cacti Lottery(暴力+期望)

    链接https://nanti.jisuanke.com/t/31455 思路 首先先枚举把剩下的数填入星号的情况(其实就是枚举星号的排列),这是对方所能知道的所有信息,然后对方将取八种决策中最优的情 ...

  4. 开启Greenplum DataBase报错:could not bind IPv4 socket: Address already in use

    在运行gpstart时无法开启服务,查看日志看到下图所示错误: 查看日志错误大概是端口已被占用,所以无法重启. 解决方法: (1)利用ipcs查看数据库占用的共享内存.(如下图所示) (2)查看数据库 ...

  5. dijkstra算法(贪心算法)——解决最短路径问题

    最短路径 给定一张带权图和其中的一个点(作为源点),求源点到其余顶点的最短路径 基本思想 1)源点u,所有顶点的集合V,集合S(S中存有的顶点,他们到源点的最短路径已经确定,源点u默认在S中),集合V ...

  6. 添加wifi adb

    https://blog.csdn.net/ouyang_peng/article/details/50370786 首先弄懂怎么设置adb wifi无线调试的功能,如下所示. 1. 手机端开启adb ...

  7. picker

    滚动选择器,现支持三种选择器,通过mode来区分,分别是普通选择器,时间选择器,日期选择器,默认是普通选择器. 普通选择器:mode = selector 属性名 类型 默认值 说明 range Ar ...

  8. MVC框架-.net-摘

    MVC模式(三层架构模式)(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller) ...

  9. (转第二方案)在 ASP.NET 環境下使用 Memcached 快速上手指南

    转自:http://blog.miniasp.com/post/2010/01/27/Memcached-for-ASPNET-Quick-Start-Guide.aspx 之前一直想研究 Memca ...

  10. Java理论学时第四节。课后作业。

    请查看String.equals()方法的实现代码,注意学习其实现方法. public class StringEquals { public static void main(String[] ar ...