### Description

​  给你一个长度为\(n\)的序列\(a_i\)和\(m\)次操作,要支持两种操作:

\(1\ l\ r\ flag\):将\([l,r]\)内的数排序,\(flag=1\)表示排成升序,否则是降序

\(2\ l\ r\):询问\([l,r]\)内的数的乘积的最高位是多少

​  

​  数据范围:\(n,m<=2*10^5\),\(1\leq a_i\leq n\)

​  

Solution

​​  首先考虑怎么处理询问:一个很棒的idea是转成维护\(lg\),取对数之后乘法就被转成了加法,我们只要维护区间\(lg\)的和\(sum\),还原的话整数部分不需要管,所以只要取\(pow(10,sum-\lfloor sum \rfloor)\)的首位即可

​  那么剩下的就是如何处理区间排序操作了

​​  显然的一点是:被\(op1\)操作过的区间一定是有序的,那么一个大胆的想法是把操作过而变得有序的区间内的数放在一起维护,具体来说就是对于每一个操作过的区间种一棵权值线段树(当然要动态开点),这样我们就可以快速查询每一块中的前缀和或者后缀和,升序降序直接整块记录一下查询的时候判断一下就好了

​  然后我们再用一棵大线段树来维护整个序列,具体来说就是将每一块(也就是每一颗权值线段树)的根节点的信息(\(lg\)和)存到这一块最左边的那个位置上,其他位置全部为\(0\)

​  这样一来我们只要实现一个线段树的分离操作和合并操作、以及快速确定一个位置\(p\)属于哪一个块(这个可以通过大线段树维护一个区间块头的\(min\)来实现)就可以了

​  修改的时候就一头一尾判一下是否需要split,然后中间一段一直合并;询问就一直跳\(l\)的块就好了,主要考虑\(l\)不是块头的情况

​  时间复杂度的话。。由于修改每次最多增加一个块,所以总复杂度是均摊的,具体的话势能分析一下(然而因为我比较菜所以只能口胡==),每次操作是均摊\(log\)的,总的就是常数巨大的\(O(nlogn)\)

​  

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ldb long double
#define Pr pair<int,int>
#define mp make_pair
using namespace std;
const int N=2e5+10;
int a[N],dir[N];//1==up 0==down
ldb lg[N];
int n,m,ans;
namespace Seg{/*{{{*/
const int N=::N*40;
int ch[N][2],rt[::N],cnt[N];
int pool[N];
ldb sum[N];
int n,tot,tp;
void pushup(int x){
cnt[x]=cnt[ch[x][0]]+cnt[ch[x][1]];
sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
}
void init(int _n){n=_n; tot=tp=0;}
void del(int x){pool[++tp]=x;}
int newnode(){
tot=tp?pool[tp--]:++tot;
cnt[tot]=sum[tot]=0; ch[tot][0]=ch[tot][1]=0;
return tot;
}
void _insert(int &x,int d,int lx,int rx,ldb delta){
if (!x) x=newnode();
++cnt[x];
sum[x]+=delta;
if (lx==rx) return;
int mid=lx+rx>>1;
if (d<=mid) _insert(ch[x][0],d,lx,mid,delta);
else _insert(ch[x][1],d,mid+1,rx,delta);
}
void insert(int x,int d){_insert(rt[x],d,1,n,lg[d]);}
void merge(int &x,int y){
if (!x||!y){x=x+y; return;}
merge(ch[x][0],ch[y][0]);
merge(ch[x][1],ch[y][1]);
sum[x]+=sum[y];
cnt[x]+=cnt[y];
del(y);
}
Pr _split(int x,int d,int lx,int rx){
if (!x||!d) return mp(0,x);
if (cnt[x]==d) return mp(x,0);
int nw=newnode();
if (lx==rx){
sum[nw]=lg[lx]*d;
cnt[nw]=d; sum[x]-=sum[nw];
cnt[x]-=cnt[nw];
return mp(nw,x);
} int lcnt=cnt[ch[x][0]],mid=lx+rx>>1;
Pr tmp;
if (d<=lcnt){
tmp=_split(ch[x][0],d,lx,mid);
ch[x][0]=tmp.second;
ch[nw][0]=tmp.first;
pushup(x);
pushup(nw);
return mp(nw,x);
}
else{
tmp=_split(ch[x][1],d-lcnt,mid+1,rx);
ch[x][1]=tmp.first;
ch[nw][1]=tmp.second;
pushup(x);
pushup(nw);
return mp(x,nw);
}
}
Pr split(int x,int d){
Pr ret;
if (dir[x])
ret=_split(rt[x],d,1,n);
else{
ret=_split(rt[x],cnt[rt[x]]-d,1,n);
swap(ret.first,ret.second);
}
return ret;
}
ldb _query(int x,int k,int lx,int rx){
if (!x||!k) return 0;
if (lx==rx) return k*lg[lx];
int lcnt=cnt[ch[x][0]],mid=lx+rx>>1;
if (k>=lcnt) return sum[ch[x][0]]+_query(ch[x][1],k-lcnt,mid+1,rx);
return _query(ch[x][0],k,lx,mid);
}
ldb query(int x,int k){
if (dir[x])
return _query(rt[x],k,1,n);
else
return sum[rt[x]]-_query(rt[x],cnt[rt[x]]-k,1,n);
}
}/*}}}*/
namespace Seg2{/*{{{*/
const int N=::N*4;
int ch[N][2],mn[N];
ldb sum[N];
int n,tot;
void pushup(int x){
sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
mn[x]=min(mn[ch[x][0]],mn[ch[x][1]]);
}
void _build(int x,int l,int r){
if (l==r){
sum[x]=Seg::sum[Seg::rt[l]];
mn[x]=l;
return;
}
int mid=l+r>>1;
ch[x][0]=++tot; _build(ch[x][0],l,mid);
ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
pushup(x);
}
void build(int _n){n=_n; tot=1; _build(1,1,n);}
void _update(int x,int d,int lx,int rx){
if (lx==rx){
mn[x]=Seg::rt[lx]?lx:n+1;
sum[x]=Seg::sum[Seg::rt[lx]];
return;
}
int mid=lx+rx>>1;
if (d<=mid) _update(ch[x][0],d,lx,mid);
else _update(ch[x][1],d,mid+1,rx);
pushup(x);
}
void update(int d){_update(1,d,1,n);}
int _get_p(int x,int d,int lx,int rx){
if (mn[x]>d) return -1;
if (lx==rx) return lx;
int mid=lx+rx>>1,ret=-1;
if (d>mid) ret=_get_p(ch[x][1],d,mid+1,rx);
if (d<=mid||ret==-1) ret=_get_p(ch[x][0],d,lx,mid);
return ret;
}
int get_p(int d){return _get_p(1,d,1,n);}//the hd which d belongs to
ldb _query(int x,int l,int r,int lx,int rx){
if (l<=lx&&rx<=r) return sum[x];
int mid=lx+rx>>1;
if (r<=mid) return _query(ch[x][0],l,r,lx,mid);
else if (l>mid) return _query(ch[x][1],l,r,mid+1,rx);
else return _query(ch[x][0],l,mid,lx,mid)+_query(ch[x][1],mid+1,r,mid+1,rx);
}
ldb query(int l,int r){return _query(1,l,r,1,n);}
}/*}}}*/ ldb get_val(int x,int l,int r){
ldb tmp1=l-1?Seg::query(x,l-1):0;
ldb tmp2=Seg::query(x,r);
return tmp2-tmp1;
}
void prework(int n){
for (int i=1;i<=n;++i) lg[i]=log10(i);
//for (int i=1;i<=n;++i) lg[i]=i;
Seg::init(n);
for (int i=1;i<=n;++i)
Seg::insert(i,a[i]);
Seg2::build(n);
}
void modify(int l,int r,int op){
using Seg::rt;
int tmp,hd,sz;
Pr pr; hd=Seg2::get_p(r);
sz=Seg::cnt[rt[hd]];
if (hd+sz-1>r){//split r
pr=Seg::split(hd,r-hd+1);
rt[hd]=pr.first; rt[r+1]=pr.second;
dir[r+1]=dir[hd];
Seg2::update(r+1);
} tmp=0;
while (hd>l){//merge mid
Seg::merge(tmp,rt[hd]);
rt[hd]=0;
Seg2::update(hd); hd=Seg2::get_p(r);
} if (hd<l){//split l
pr=Seg::split(hd,l-hd);
rt[hd]=pr.first; rt[l]=pr.second;
Seg2::update(hd);
} Seg::merge(rt[l],tmp);
dir[l]=op;
Seg2::update(l);
}
int query(int l,int r){
using Seg::rt;
int hd=Seg2::get_p(r);
ldb ret;
if (hd<=l){//same
ret=get_val(hd,l-hd+1,r-hd+1);
}
else{
ret=Seg2::query(l,hd-1);
ret+=get_val(hd,1,r-hd+1); hd=Seg2::get_p(l);
if (hd<l)//l --> not hd
ret+=get_val(hd,l-hd+1,Seg::cnt[rt[hd]]);
} ret=pow(10,ret-floor(ret));
return (int)ret;
} int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int op,l,r,dir;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) scanf("%d",a+i);
prework(n);
for (int i=1;i<=m;++i){
scanf("%d%d%d",&op,&l,&r);
if (op==1){
scanf("%d",&dir);
modify(l,r,dir);
}
else{
ans=query(l,r);
printf("%d\n",ans);
}
}
}

Philosopher的更多相关文章

  1. Philosopher’s Walk(递归)

    In Programming Land, there are several pathways called Philosopher’s Walks for philosophers to have ...

  2. Philosopher’s Walk --DFS

    题意: Philosopher’s Walk 图,告诉你step返回位置. 思路: 按四个块DFS #define IOS ios_base::sync_with_stdio(0); cin.tie( ...

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

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

  4. Philosopher(set 线段树合并)

    直接维护乘积是肯定不可行的, 精度会爆炸, 于是我们来维护对数的和, 最后来计算最高位即可 那么转换成区间求和, 区间排序 区间排序的方式可以采用线段树维护最大递增块来解决,外层用set来维护线段树的 ...

  5. 【英语学习】2016.09.11 Culture Insider: Teacher's Day in ancient China

      Culture Insider: Teacher's Day in ancient China 2016-09-10 CHINADAILY Today is the 32nd Chinese Te ...

  6. 第一篇英文短文《It All Starts With A Dream》

    http://www.ximalaya.com/#/17209107/sound/6883165 Dreaming. Do you or don’t you? Do you dream about t ...

  7. cs107

    基本类型:bool,char,short,int,long,float,double 对于char,short,int,long: 多字节类型赋值给少字节类型,对低字节的细节感兴趣,位模式拷贝. 少字 ...

  8. Python 3.X简史——记录3.0之后的重要更新

    Python 3.0在2008年12月3日正式发布,在之后又经历了多个小版本(3.1,3.2,3.3……),本文梳理Python 3.0之后的新特性. 其实每个版本都有大量更新,都写出来要几百页,这里 ...

  9. 【英语魔法俱乐部——读书笔记】 3 高级句型-简化从句&倒装句(Reduced Clauses、Inverted Sentences) 【完结】

    [英语魔法俱乐部——读书笔记] 3 高级句型-简化从句&倒装句(Reduced Clauses.Inverted Sentences):(3.1)从属从句简化的通则.(3.2)形容词从句简化. ...

随机推荐

  1. 《网络对抗》Exp7 网络欺诈防范

    20155336<网络对抗>Exp7 网络欺诈防范 实验内容 本实践的目标理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法.具体实践有 简单应用SET工具建立冒名网站 (1分 ...

  2. 【WPF】给TextBox添上Label

    原文:[WPF]给TextBox添上Label 引言     在客户端开发中,要说出现频率大的控件,必定有TextBox的身影.然而在TextBox的旁边通常得有个基友Label,形影不离.为此,我们 ...

  3. Ubuntu中程序部署时无法加载动态库的解决方法

    Ubuntu下修改环境变量的三种方法 添加环境变量无法解决,可尝试如下操作: sudo vim /etc/ld.so.conf 在ld.so.conf中加入动态库的目录... 然后 sudo ldco ...

  4. [BZOJ2687]交与并[决策单调性]

    题意 给定 \(n\) 个区间,我们定义区间集合 \(S(|S|>1)\) 的权值为 区间交 \(\times\) 区间并,找出权值最大的区间集合. \(n\le 10^6\) 分析 首先排除区 ...

  5. ABPZERO介绍

    内容 首先我们创建一个名为"Acme.PhoneBook"的项目. 本文档是指南会同步开发您的项目. 我们建议你在开发之前准备备份下这份初始项目. 因为abpZero是基于abp的 ...

  6. Js_cookie保存登录名

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...

  7. OD之修改文件标题(一)

    OD是逆向工程中的一个重要工具,逆向工程调试说明具体请参考:百度百科,OD介绍,当然就我了解而言,俗话就是破解软件,市面上的什么破解版,精简版啥的基本都是通过这种技术的,但是这并不能一概而论说逆向工程 ...

  8. 11.7 Daily Scrum(周末暂停两天Daily Scrum)

    由于APEC放假,有些成员离校了,他们那部分的任务会暂时拖后一些,之后会加班加点赶工. 另外,每个人的任务还是相对独立,离校成员的任务进度不会对其他成员的进度造成很大影响.   Today's tas ...

  9. Daily Scrum 12.22

    姓名 上周末任务 今日任务 刘垚鹏 完善和增加quiz页面的过滤功能 完善和增加quiz页面的过滤功能 王骜 对问答功能的修复 对问答功能的修复 林旭鹏 存储文件路径太长导致bug修复 存储文件路径太 ...

  10. 《Linux内核分析》 第四周

    [李行之 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] <Linux内 ...