• Rikka with Sequence


    题意:

    给一长度为n的序列,维护三个操作:区间开根,区间加,区间求和。

    解法:

    注意到本题关键在于区间开根:

    对于一个数字,只要进行$O(loglogT)$次开根即会变为1。

    考虑线段树,对于线段数上的点维护$maxv$,$minv$。

    对于$[sqrt{maxv}] = [sqrt{minv}]$的点我们直接执行区间染色。

    如果我们在开根时经过这个点则有$maxv - minv$减小,且只会经过$O(loglog(maxv-minv))$次。

    考虑区间加的操作,相当于只是让$O(logn)$个位于 线段树上 修改区间边界上的两条链上的点 的$maxv-minv$增大,

    这样会产生$O(logn*loglog(maxv-minv))$次的后续操作

    注意到可能会出现开根后差值不变的情况,这样会导致 线段树上 修改区间内 的点的$maxv-minv$可能不变

    导致效率退化。

    特判一下,并将其转化为区间加上$sqrt{maxv} - maxv$。

    维护两个标记$addv$与$setv$,$setv$标记优先级大。

    这样,总效率$O(nlogn*loglogn)$

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 
      6 #define N 100010
      7 #define LL long long
      8 #define l(x) ch[x][0]
      9 #define r(x) ch[x][1]
     10 
     11 using namespace std;
     12 
     13 int n,m,totn;
     14 int a[N];
     15 int ch[N<<1][2];
     16 LL addv[N<<1],maxv[N<<1],minv[N<<1],sumv[N<<1],setv[N<<1];
     17 
     18 void push(int x,int l,int r)
     19 {
     20     if(l==r) return;
     21     int mid=(l+r)>>1;
     22     LL lsiz = (mid-l+1);
     23     LL rsiz = (r-mid);
     24     if(setv[x])
     25     {
     26         setv[l(x)]=setv[x];
     27         maxv[l(x)]=setv[x];
     28         minv[l(x)]=setv[x];
     29         addv[l(x)]=0;
     30         sumv[l(x)]=lsiz*setv[x];
     31         
     32         setv[r(x)]=setv[x];
     33         maxv[r(x)]=setv[x];
     34         minv[r(x)]=setv[x];
     35         addv[r(x)]=0;
     36         sumv[r(x)]=rsiz*setv[x];
     37         setv[x]=0;
     38     }
     39     if(addv[x])
     40     {
     41         if(setv[l(x)]) setv[l(x)]+=addv[x];
     42         else addv[l(x)]+=addv[x];
     43         maxv[l(x)]+=addv[x];
     44         minv[l(x)]+=addv[x];
     45         sumv[l(x)]+=lsiz*addv[x];
     46         
     47         if(setv[r(x)]) setv[r(x)]+=addv[x];
     48         else addv[r(x)]+=addv[x];
     49         maxv[r(x)]+=addv[x];
     50         minv[r(x)]+=addv[x];
     51         sumv[r(x)]+=rsiz*addv[x];
     52         addv[x]=0;
     53     }
     54 }
     55 
     56 void update(int x)
     57 {
     58     maxv[x] = max(maxv[l(x)], maxv[r(x)]);
     59     minv[x] = min(minv[l(x)], minv[r(x)]);
     60     sumv[x] = sumv[l(x)] + sumv[r(x)];
     61 }
     62 
     63 int build(int l,int r)
     64 {
     65     int x=++totn;
     66     addv[x]=0;
     67     setv[x]=0;
     68     if(l==r)
     69     {
     70         maxv[x]=a[l];
     71         minv[x]=a[l];
     72         sumv[x]=a[l];
     73         return x;
     74     }
     75     int mid=(l+r)>>1;
     76     l(x)=build(l,mid);
     77     r(x)=build(mid+1,r);
     78     update(x);
     79     return x;
     80 }
     81 
     82 void solve(int x,int l,int r)
     83 {
     84     push(x,l,r);
     85     if(maxv[x]==1) return;
     86     LL tmp1 = (LL)sqrt(maxv[x]+0.5);
     87     LL tmp2 = (LL)sqrt(minv[x]+0.5);
     88     if(tmp1==tmp2)
     89     {
     90         setv[x]=tmp1;
     91         maxv[x]=tmp1;
     92         minv[x]=tmp1;
     93         sumv[x]=(r-l+1LL)*tmp1;
     94         return;
     95     }
     96     if(maxv[x]==minv[x]+1 && tmp1==tmp2+1)
     97     {
     98         addv[x]=tmp1-maxv[x];
     99         maxv[x]+=addv[x];
    100         minv[x]+=addv[x];
    101         sumv[x]+=(r-l+1LL)*addv[x];
    102         return;
    103     }
    104     int mid=(l+r)>>1;
    105     solve(l(x),l,mid);
    106     solve(r(x),mid+1,r);
    107     update(x);
    108 }
    109 
    110 void change(int x,int l,int r,int ql,int qr)
    111 {
    112     push(x,l,r);
    113     if(ql<=l && r<=qr)
    114     {
    115         solve(x,l,r);
    116         return;
    117     }
    118     int mid=(l+r)>>1;
    119     if(ql<=mid) change(l(x),l,mid,ql,qr);
    120     if(mid<qr) change(r(x),mid+1,r,ql,qr);
    121     update(x);
    122 }
    123 
    124 void add(int x,int l,int r,int ql,int qr,LL qv)
    125 {
    126     push(x,l,r);
    127     if(ql<=l && r<=qr)
    128     {
    129         addv[x]=qv;
    130         maxv[x]+=qv;
    131         minv[x]+=qv;
    132         sumv[x]+=qv*(r-l+1LL);
    133         return;
    134     }
    135     int mid=(l+r)>>1;
    136     if(ql<=mid) add(l(x),l,mid,ql,qr,qv);
    137     if(mid<qr) add(r(x),mid+1,r,ql,qr,qv);
    138     update(x);
    139 }
    140 
    141 LL qsum(int x,int l,int r,int ql,int qr)
    142 {
    143     push(x,l,r);
    144     if(ql<=l && r<=qr) return sumv[x];
    145     int mid=(l+r)>>1;
    146     LL ans=0;
    147     if(ql<=mid) ans+=qsum(l(x),l,mid,ql,qr);
    148     if(mid<qr) ans+=qsum(r(x),mid+1,r,ql,qr);
    149     update(x);
    150     return ans;
    151 }
    152 
    153 int main()
    154 {
    155     while(~scanf("%d%d",&n,&m))
    156     {
    157         totn=0;
    158         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    159         build(1,n);
    160         int cmd,l,r,x;
    161         for(int i=1;i<=m;i++)
    162         {
    163             scanf("%d%d%d",&cmd,&l,&r);
    164             if(cmd==1)
    165             {
    166                 scanf("%d",&x);
    167                 add(1,1,n,l,r,x);
    168             }
    169             else if(cmd==2) change(1,1,n,l,r);
    170             else printf("%lld
    ",qsum(1,1,n,l,r));
    171         }
    172     }
    173     return 0;
    174 }
    View Code
  • 相关阅读:
    hdu 4707 Pet
    hdu 3584 Cube (三维树状数组)
    poj 2155 Matrix (树状数组)
    poj 1195 Mobile phones (树状数组)
    工厂方法模式
    简单工厂模式
    关于设计模式
    UML类图
    UML
    【转载】UML用例图
  • 原文地址:https://www.cnblogs.com/lawyer/p/6567612.html
Copyright © 2020-2023  润新知