【xsy2194】Philosopher set+线段树合并
题目大意:给你一个长度为$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+线段树合并的更多相关文章
- [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】
题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动 ...
- [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】
题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换 ...
- 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). 复杂度看起来不高, ...
- BZOJ2733 [HNOI2012]永无乡 【线段树合并】
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)
[bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...
- bzoj3702二叉树 线段树合并
3702: 二叉树 Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 600 Solved: 272[Submit][Status][Discuss] ...
- BZOJ_2212_[Poi2011]Tree Rotations_线段树合并
BZOJ_2212_[Poi2011]Tree Rotations_线段树合并 Description Byteasar the gardener is growing a rare tree cal ...
- B20J_2733_[HNOI2012]永无乡_权值线段树合并
B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...
- BZOJ_3307_雨天的尾巴_线段树合并+树上差分
BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...
随机推荐
- Java 获取最近时间
public static String getStatetime() throws ParseException{ SimpleDateFormat sdf = new SimpleDateForm ...
- WEB上传大文件解决方案
众所皆知,web上传大文件,一直是一个痛.上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的. 本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路.下面贴出简易 ...
- Remote Debugging (1)
The client/server design of the Java debugger allows you to launch a Java program from computer on y ...
- 批处理FINDSTR正则表达式用法实例分析
1.findstr . 2.txt 或 Findstr "." 2.txt 从文件2.txt中查找任意字符,不包括空字符或空行 2.findstr .* 2.txt 或 finds ...
- mysql 数据类型及java对应关系
http://www.cnblogs.com/jerrylz/p/5814460.html Java数据类型和MySql数据类型对应表 http://www.cnblogs.com/yiwd/p ...
- CentOS 6 安装Redmine
Redmine是一个灵活的项目管理web应用,采用Ruby on Rails框架开发.Redmine是典型的web 2.0网站,项目管理系统的后起之秀.Redmine支持多项目,灵活的角色权限管理,灵 ...
- 我看Windows 8.1
在大家惊叹于Windows 8的大胆创新之时,Windows 8.1却已然来到.在公布了Preview之后,笔者便迫不及待地进行了安装,并在这里简单的说说最直观的感受. 提到Windows 8,不得不 ...
- Eclipse运行wordcount步骤
Eclipse运行wordcount步骤 第一步:建立工程,导入代码. 第二步:建立文件写入数据(以空格分开),并上传到hdfs上. 1.创建文件并写入数据: 2.上传hdfs 在hadoop权限下就 ...
- bootstrap1相关学习文档
<em>Bootstrap 框架</em> //倾斜 4.对齐 //设置文 ...
- Swift简单实现一个常规条款、免责声明文字+带有链接的展示形式
效果: IMG_F08DABE063A6-1.jpeg class DisclamerView: UIView { //@objc weak var vc:UIViewController? // ...