题目大意:给你一个长度为$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. Java 获取最近时间

    public static String getStatetime() throws ParseException{ SimpleDateFormat sdf = new SimpleDateForm ...

  2. WEB上传大文件解决方案

    众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路.下面贴出简易 ...

  3. Remote Debugging (1)

    The client/server design of the Java debugger allows you to launch a Java program from computer on y ...

  4. 批处理FINDSTR正则表达式用法实例分析

    1.findstr . 2.txt 或 Findstr "." 2.txt 从文件2.txt中查找任意字符,不包括空字符或空行 2.findstr .* 2.txt 或 finds ...

  5. mysql 数据类型及java对应关系

    http://www.cnblogs.com/jerrylz/p/5814460.html    Java数据类型和MySql数据类型对应表 http://www.cnblogs.com/yiwd/p ...

  6. CentOS 6 安装Redmine

    Redmine是一个灵活的项目管理web应用,采用Ruby on Rails框架开发.Redmine是典型的web 2.0网站,项目管理系统的后起之秀.Redmine支持多项目,灵活的角色权限管理,灵 ...

  7. 我看Windows 8.1

    在大家惊叹于Windows 8的大胆创新之时,Windows 8.1却已然来到.在公布了Preview之后,笔者便迫不及待地进行了安装,并在这里简单的说说最直观的感受. 提到Windows 8,不得不 ...

  8. Eclipse运行wordcount步骤

    Eclipse运行wordcount步骤 第一步:建立工程,导入代码. 第二步:建立文件写入数据(以空格分开),并上传到hdfs上. 1.创建文件并写入数据: 2.上传hdfs 在hadoop权限下就 ...

  9. bootstrap1相关学习文档

    <em>Bootstrap 框架</em>                                                    //倾斜 4.对齐 //设置文 ...

  10. Swift简单实现一个常规条款、免责声明文字+带有链接的展示形式

    效果:   IMG_F08DABE063A6-1.jpeg class DisclamerView: UIView { //@objc weak var vc:UIViewController? // ...