【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类型的物品.完成 所有发放后 ...
随机推荐
- Opencv基本数据类型
1.OpenCV中数据类型和常用数据类型对应 Mat<uchar> CV_8U Mat<char> ...
- 【RabbitMQ】三种类型交换器 Fanout,Direct,Topic(转)
出处:https://blog.csdn.net/fxq8866/article/details/62049393 RabbitMQ服务器会根据路由键将消息从交换器路由到队列中,如何处理投递到多个队列 ...
- redis 部分操作
http://pan.baidu.com/s/1eRXdbUy 下载安装地址 打开一个cmd窗口,使用cd命令切换到指定目录(D:\ruanjian\redis\64bit)运行 redis-ser ...
- 第31章:MongoDB-索引--复合索引
①复合索引 对多个字段创建索引被称为复合索引或者组合索引 ②创建组合索引 创建组合索引(以后台模式创建) db.user.ensureIndex({"username": 1, & ...
- 怎么让挨着的两input之间没有空隙?
问题:在写选项卡的时候,用input做点击事件的切换时,两个input之间会有空隙,使用margin/padding为0或者为负数依旧如此 → 解决:我脑慢的最后才想到是空格影响的,呵呵呵.
- Jersey RESTful WebService框架学习(六)接收MultivaluedMap类型参数
现在的web开发中有些工程会觉得实体bean的架构会比较重,现在的持久层的框架的特点也层出不穷,核心思想的ORM在此基础上,提供了很多便捷操作,mybatis,jfinal(内部持久层框架)之类的也诞 ...
- AngularJS监听数组变化
我们在使用angualr的监听时候,业务的需要我们会去监听一个数组的某一个值得变化,再写逻辑代码.然而我们在使用$scope.$watch("",function(){ })时候会 ...
- Docker Swarm集群部署
一.系统环境 1)服务器环境 节点名称 IP 操作系统 内核版本 manager 172.16.60.95 CentOs7 4.16.1-1.el7.elrepo.x86_64 node-01 172 ...
- XA: 事务和两阶段提交
本文原文连接:http://blog.csdn.net/bluishglc/article/details/7612811 ,转载请注明出处! 1.XA XA是由X/Open组织提出的两阶段提交协议, ...
- 在Win环境下配置java的环境进行开发步骤
1.下载官方JDK,网址如下 http://www.oracle.com/technetwork/java/javase/downloads/index.html