题目大意
区间排序,区间求乘积十进制下的最高位。
做法
先转化询问。
对所有数取
log10
l
o
g
10
。
那么乘法转化为加法。
设取
log
l
o
g
后和为
x
x
,答案显然是。
现在问题就是,区间排序,区间求和,怎么做?
可以维护若干个排序块,这个可以用平衡树维护。
每个排序块维护一颗权值线段树。
每次区间排列,分裂边缘块的线段树,再把整块的线段树合并起来,然后建立一个新的排序块。
设势函数表示线段树节点数,初始时为n log n,一次线段树分裂会增加log个线段树节点,势函数加log n。每次线段树合并若遍历
k
k
个节点,势函数减少。
因此复杂度为
O(n log n)
O
(
n
l
o
g
n
)
。
注意线段树的空间可以回收循环利用。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define nxt(x) (x==n?0:x+1)
#define nt(x) (x==maxtot-10?0:x+1)
using namespace std;
typedef long double db;
const int maxn=200000+10,maxtot=15000000+10;
const db eps=1e-8;
db sum[maxtot],num[maxn],key[maxn],p[maxn];
int root[maxn],val[maxn],L[maxn],R[maxn],tree[maxn][2],father[maxn],ld[maxn],a[maxn],b[maxn];
int size[maxtot],left[maxtot],right[maxtot],dl[maxtot];
int i,j,k,l,r,x,y,t,n,m,tot,top,head,tail,hd,tl,rot,now,wdc;
db ans;
bool czy;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
bool cmp(int x,int y){
return p[x]<p[y];
}
void insert(int &x,int l,int r,int a){
if (!x) x=++tot;
size[x]++;
sum[x]+=p[a];
if (l==r) return;
int mid=(l+r)/2;
if (a<=mid) insert(left[x],l,mid,a);else insert(right[x],mid+1,r,a);
}
db query(int x,int l,int r,int a,int b){
if (a==1&&b==size[x]) return sum[x];
int mid=(l+r)/2;
if (size[left[x]]>=b) return query(left[x],l,mid,a,b);
else if (size[left[x]]<a) return query(right[x],mid+1,r,a-size[left[x]],b-size[left[x]]);
else return query(left[x],l,mid,a,size[left[x]])+query(right[x],mid+1,r,1,b-size[left[x]]);
}
db ask(int x,int l,int r){
if (val[x]==1) l=l-L[x]+1,r=r-L[x]+1;
else{
l=R[x]-l+1;r=R[x]-r+1;
swap(l,r);
}
return query(root[x],1,n,l,r);
}
void update(int x){
num[x]=num[tree[x][0]]+num[tree[x][1]]+key[x];
}
int pd(int x){
return tree[father[x]][1]==x;
}
void rotate(int x){
int y=father[x],z=pd(x);
father[x]=father[y];
if (father[y]) tree[father[y]][pd(y)]=x;
tree[y][z]=tree[x][1-z];
if (tree[x][1-z]) father[tree[x][1-z]]=y;
tree[x][1-z]=y;
father[y]=x;
update(y);
update(x);
}
void splay(int x,int y){
while (father[x]!=y){
if (father[father[x]]!=y)
if (pd(x)==pd(father[x])) rotate(father[x]);else rotate(x);
rotate(x);
}
}
int find(int x,int y){
if (L[x]<=y&&y<=R[x]) return x;
if (y<L[x]) return find(tree[x][0],y);
else return find(tree[x][1],y);
}
void work(int l,int r,int &x,int &y){
x=find(rot,l);
splay(x,0);
rot=x;
y=find(rot,r);
if (y!=x) splay(y,x);
}
int getid(){
hd=nxt(hd);
return ld[hd];
}
int getnew(){
if (head==tail) return ++tot;
head=nt(head);
return dl[head];
}
int merge(int x,int y,int l,int r){
if (!x||!y) return x+y;
int mid=(l+r)/2;
left[x]=merge(left[x],left[y],l,mid);
right[x]=merge(right[x],right[y],mid+1,r);
size[x]=size[left[x]]+size[right[x]];
sum[x]=sum[left[x]]+sum[right[x]];
tail=nt(tail);
dl[tail]=y;
return x;
}
void travel(int x){
if (!x) return;
tl=nxt(tl);
ld[tl]=x;
now=merge(now,root[x],1,n);
travel(tree[x][0]);
travel(tree[x][1]);
}
void cr(int &x,int y){
if (!x){
x=y;
return;
}
if (L[y]<L[x]){
cr(tree[x][0],y);
father[tree[x][0]]=x;
update(x);
}
else{
cr(tree[x][1],y);
father[tree[x][1]]=x;
update(x);
}
}
void del(int x){
tl=nxt(tl);
ld[tl]=x;
splay(x,0);
if (!tree[x][0]){
if (!tree[x][1]){
rot=0;
return;
}
father[tree[x][1]]=0;
rot=tree[x][1];
}
else{
int t=tree[x][0];
while (tree[t][1]) t=tree[t][1];
splay(t,x);
if (!tree[x][1]){
father[t]=0;
rot=t;
}
else{
father[t]=0;
father[tree[x][1]]=t;
tree[t][1]=tree[x][1];
update(t);
rot=t;
}
}
}
void split(int x,int l,int r,int k,int &a,int &b){
if (!k){
a=0;
b=x;
return;
}
if (k==size[x]){
a=x;
b=0;
return;
}
int mid=(l+r)/2;
int nx=getnew();
if (k<=size[left[x]]){
split(left[x],l,mid,k,a,b);
left[nx]=b;
right[nx]=right[x];
left[x]=a;
right[x]=0;
size[x]=size[left[x]]+size[right[x]];
sum[x]=sum[left[x]]+sum[right[x]];
size[nx]=size[left[nx]]+size[right[nx]];
sum[nx]=sum[left[nx]]+sum[right[nx]];
a=x;b=nx;
}
else{
split(right[x],mid+1,r,k-size[left[x]],a,b);
left[nx]=0;
right[nx]=b;
right[x]=a;
size[x]=size[left[x]]+size[right[x]];
sum[x]=sum[left[x]]+sum[right[x]];
size[nx]=size[left[nx]]+size[right[nx]];
sum[nx]=sum[left[nx]]+sum[right[nx]];
a=x;b=nx;
}
}
void fen(int x,int l,int r){
int ca=val[x],LL=L[x],RR=R[x];
int ly=l,ry=r;
if (val[x]==1) l=l-L[x]+1,r=r-L[x]+1;
else{
l=R[x]-l+1;r=R[x]-r+1;
swap(l,r);
}
del(x);
if (l==1&&r==R[x]-L[x]+1){
now=merge(now,root[x],1,n);
return;
}
int lx,llx,rx,mx,k;
split(root[x],1,n,r,lx,rx);
split(lx,1,n,l-1,llx,mx);
lx=llx;
now=merge(now,mx,1,n);
if (ca==0) swap(lx,rx);
if (lx){
k=getid();
root[k]=lx;
L[k]=LL;R[k]=ly-1;
tree[k][0]=tree[k][1]=father[k]=0;
key[k]=num[k]=sum[root[k]];
val[k]=ca;
cr(rot,k);
}
if (rx){
k=getid();
root[k]=rx;
L[k]=ry+1;R[k]=RR;
tree[k][0]=tree[k][1]=father[k]=0;
key[k]=num[k]=sum[root[k]];
val[k]=ca;
cr(rot,k);
splay(k,0);
rot=k;
}
}
void deb(int x){
if (!x) return;
deb(tree[x][0]);
//printf("%d %d %d\n",x,L[x],R[x]);
if (L[x]==wdc+1) wdc=R[x];
else{
czy=0;
return;
}
deb(tree[x][1]);
}
int main(){
freopen("zkb.in","r",stdin);freopen("zkb.out","w",stdout);
n=read();m=read();
fo(i,1,n){
a[i]=read();
//p[i]=log(a[i])/log(10);
p[i]=log(a[i]);
}
fo(i,1,n) a[i]=i;
sort(a+1,a+n+1,cmp);
sort(p+1,p+n+1);
fo(i,1,n) b[a[i]]=i;
rot=1;
fo(i,1,n){
L[i]=R[i]=i;
if (i<n) tree[i][1]=i+1;
father[i]=i-1;
insert(root[i],1,n,b[i]);
num[i]=key[i]=p[b[i]];
}
fd(i,n-1,1) num[i]+=num[i+1];
/*deb(rot);
printf("\n");*/
while (m--){
//printf("%d\n",m);
if (m==778){
m=m;
}
t=read();
if (t==1){
l=read();r=read();t=read();
work(l,r,x,y);
now=0;
if (x==y){
fen(x,l,r);
k=getid();
root[k]=now;
L[k]=l;R[k]=r;
tree[k][0]=tree[k][1]=father[k]=0;
key[k]=num[k]=sum[now];
val[k]=t;
cr(rot,k);
splay(k,0);
rot=k;
}
else{
travel(tree[y][0]);
tree[y][0]=0;
update(y);
update(x);
fen(x,l,R[x]);
fen(y,L[y],r);
k=getid();
root[k]=now;
L[k]=l;R[k]=r;
tree[k][0]=tree[k][1]=father[k]=0;
key[k]=num[k]=sum[now];
val[k]=t;
cr(rot,k);
splay(k,0);
rot=k;
}
/*czy=1;wdc=0;
deb(rot);
if (!czy){
printf("%d\n",m);
break;
}*/
}
else{
l=read();r=read();
work(l,r,x,y);
if (x==y) ans=ask(x,l,r);
else{
ans=num[tree[y][0]];
ans+=ask(x,l,R[x]);
ans+=ask(y,L[y],r);
}
ans=ans/log(10);
ans=ans-floor(ans);
ans=pow(10,ans);
ans+=eps;
printf("%d\n",int(floor(ans)));
}
}
}