zoukankan      html  css  js  c++  java
  • 【xsy2194】Philosopher set+线段树合并

    题目大意:给你一个长度为$n$的序列,有$m$次操作,每次操作是以下两种之一:

    对某个区间内的数按照升序/降序排序,询问某个区间内数的积在十进制下首位数字是多少。

    数据范围:$n,m≤2 imes 10^5$ 序列内数字均不大于$n$。

    我们先考虑下如何实现查询首位数字

    我们发现如果直接乘的话精度损失实在太大,我们考虑把所有读入的数字全部转成对数,直接加起来。

    设某个区间内对数和为$x$,那么该区间内数的积的首位为$lfloor 10^{x-lfloor x floor} floor$。

    下面考虑如何做排序操作

    我们先种一堆的线段树,满足每一棵线段树维护的是一个已经按照升序/降序排序好的区间(内层线段树存储该区间内放了值为哪些的数)

    我们对某个区间进行排序的时候,我们要取出若干个线段树,满足这些线段树构成的区间恰好为需要排序的区间。

    然后我们通过线段树合并将这些区间合并为一个区间即可,最后打上这个区间的升序/降序标记

    然而有些线段树被我们需要操作的区间部分包含。

    这种情况下就需要把这棵线段树从中间某个位置开始拆开。

    考虑到一棵线段树所代表的区间内的数都是排序好的,我们可以根据升序/降序标记来拆开这棵线段树。

    每一棵线段树的根我们可以开一个$set$来存储,每一棵线段树内的对数和我们可以单独打在一个树状数组上。

    在查询答案的时候,我们按照上面做排序的方法,拆出若干棵线段树,然后直接在线段树上查询即可。

    时间复杂度:$O(nlog^2 n)$

      1 #include<bits/stdc++.h>
      2 #define D long double
      3 #define M (1<<18)
      4 #define lowbit(x) (x&(-x))
      5 #define N 20000005
      6 #define S set<node>::iterator
      7 #define eps (1e-8)
      8 using namespace std;
      9 
     10 int n,m; D c[M]={0}; void add(int x,D k){for(int i=x;i<=n;i+=lowbit(i)) c[i]+=k;}
     11 D query(int x){D k=0; for(int i=x;i;i-=lowbit(i)) k+=c[i]; return k;}
     12 int num[M]={0}; D val[M]={0};
     13 
     14 struct node{
     15     int l,r,rt,op;
     16     node(int ll=0,int rr=0,int RT=0,int OP=0){l=ll; r=rr; rt=RT; op=OP;}
     17     friend bool operator <(node a,node b){return a.l<b.l;}
     18 };set<node> s;
     19 
     20 int lc[N]={0},rc[N]={0},cnt[N]={0},use=0; D sum[N]={0};
     21 void pushup(int x){
     22     cnt[x]=cnt[lc[x]]+cnt[rc[x]];
     23     sum[x]=sum[lc[x]]+sum[rc[x]];
     24 }
     25 int merge(int x,int y){
     26     if(!x||!y) return x|y;
     27     lc[x]=merge(lc[x],lc[y]);
     28     rc[x]=merge(rc[x],rc[y]);
     29     cnt[x]=cnt[x]+cnt[y];
     30     sum[x]=sum[x]+sum[y];
     31     return x;
     32 }
     33 
     34 S Ins(node x){add(x.l,sum[x.rt]);return s.insert(x).first;}
     35 void Del(S it){add(it->l,-sum[it->rt]);s.erase(it);}
     36 
     37 void split(int x,int &rt1,int &rt2,int l,int r,int k){
     38     rt1=++use; rt2=++use;
     39     if(l==r){
     40         cnt[rt1]=k; sum[rt1]=val[l]*k;
     41         cnt[rt2]=cnt[x]-cnt[rt1];
     42         sum[rt2]=sum[x]-sum[rt1];
     43         return;
     44     }
     45     int mid=(l+r)>>1;
     46     if(cnt[lc[x]]>=k){
     47         rc[rt2]=rc[x];
     48         split(lc[x],lc[rt1],lc[rt2],l,mid,k);
     49     }else{
     50         lc[rt1]=lc[x];
     51         split(rc[x],rc[rt1],rc[rt2],mid+1,r,k-cnt[lc[x]]);
     52     }
     53     pushup(rt1); pushup(rt2);
     54 }
     55 S split(int x){
     56     if(x>n) return s.end();
     57     S it=s.upper_bound(node(x,0,0,0)); it--;
     58     node hh=*it; if(hh.l==x) return it;
     59     int rt1,rt2;
     60     if(!hh.op) split(hh.rt,rt1,rt2,1,n,x-hh.l);
     61     else split(hh.rt,rt2,rt1,1,n,hh.r-x+1);
     62     Del(it);
     63     Ins(node(hh.l,x-1,rt1,hh.op));
     64     return Ins(node(x,hh.r,rt2,hh.op));
     65 }
     66 
     67 void updata(int l,int r,int op){
     68     S L=split(l); split(r+1); int rt=0;
     69     for(S it=L;it!=s.end()&&(it->l)<=r;Del(it++)){
     70         rt=merge(rt,it->rt);
     71     }
     72     Ins(node(l,r,rt,op));
     73 }
     74 int calc(int l,int r){
     75     S L=split(l),R=split(r+1); R--;
     76     D ans=query(R->r)-query(L->l-1);
     77     D out=pow(10,ans-floorl(ans)+eps);
     78     return floorl(out);
     79 }
     80 
     81 void build(int &x,int l,int r,int k){
     82     x=++use; cnt[x]++; sum[x]+=val[k];
     83     if(l==r) return; int mid=(l+r)>>1;
     84     if(k<=mid) build(lc[x],l,mid,k); 
     85     else build(rc[x],mid+1,r,k);
     86 }
     87 
     88 int main(){
     89     scanf("%d%d",&n,&m);
     90     for(int i=1;i<=n;i++) scanf("%d",num+i);
     91     for(int i=1;i<=n;i++) val[i]=log10(i);
     92     for(int i=1;i<=n;i++){
     93         int now; build(now,1,n,num[i]);
     94         Ins(node(i,i,now,0));
     95     }
     96     while(m--){
     97         int op,l,r; scanf("%d%d%d",&op,&l,&r);
     98         if(op==2) printf("%d
    ",calc(l,r));
     99         else{
    100             scanf("%d",&op); op^=1;
    101             updata(l,r,op);
    102         }
    103     }
    104 }
  • 相关阅读:
    边框的作用之产生相对margin
    css3 实现切换显示隐藏效果
    Vue 获取数据、事件对象、todolist
    Vue 双向数据绑定、事件介绍以及ref获取dom节点
    Vue 目录结构分析 数据绑定 绑定属性 循环渲染数据 数据渲染
    Vue 安装环境创建项目
    进程&线程
    生成Excel
    JQuery input file 上传图片
    0908期 HTML 样式表属性
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10582462.html
Copyright © 2011-2022 走看看