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\n",qsum(1,1,n,l,r));
171         }
172     }
173     return 0;
174 }

时间: 2024-11-07 20:00:52

Rikka with Sequence的相关文章

HDU 5828 Rikka with Sequence(线段树 开根号)

Rikka with Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2777    Accepted Submission(s): 503 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situati

【HDU 5828】Rikka with Sequence(线段树)

[HDU 5828]Rikka with Sequence(线段树) Rikka with Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2311    Accepted Submission(s): 391 Problem Description As we know, Rikka is poor at math.

判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence

1 // 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence 2 // 题意:三种操作,1增加值,2开根,3求和 3 // 思路:这题与HDU 4027 和HDU 5634 差不多 4 // 注意开根号的话,遇到极差等于1的,开根号以后有可能还是差1.如 5 // 2 3 2 3... 6 // 8 9 8 9... 7 // 2 3 2 3... 8 // 8 9 8 9... 9 // 剩下就是遇到区间相等的话,就直接开根号不往下传 10 11 12

hdu 5204 Rikka with sequence 智商不够系列

Rikka with sequence Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5204 Description 众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:现在有一个序列,因为这个序列很任性,开始时空的.接下来发生了n个事件,每一个事件是以下两种之一:1.勇太利用黑炎龙的力量在序列的开头.结尾以及每相邻两个元素之间都插入

hdu 5204 Rikka with sequence

题意: 众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的: 如果一个无重边无自环的无向图的每个联通块都存在一条回路经过这个联通分量所有边一次且仅一次,那么就称这个无向图是优美的.请问有n个点且边数不少于m的优美的图有多少个?(在这题中,我们认为这n个点是本质不同的) 当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗? 限制: 1 <= n <= 1e5; 1 <= L <= R <= 1e18; 1 <= w <=

hdu 5204 Rikka with sequence(BestCoder Round #37)

Rikka with sequence                                                        Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 378    Accepted Submission(s): 75 Problem Description As we know, Rikk

2016暑假多校联合---Rikka with Sequence (线段树)

2016暑假多校联合---Rikka with Sequence (线段树) Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them: Yuta has an array A with n numbers. Then he make

HDU 5828 Rikka with Sequence

好久没写线段树了,这题作为一个回味.. 第一种操作的话,就是一个延迟标记. 第二种操作可以暴力更新下去,但是有一个优化,如果某区间内所有值都是一样的,那么到此结束,不要继续往下面暴力更新了. 这样一来的话,pushDown的时候要注意一下,如果该区间内所有值都一样,那么延迟标记不要往下扔了,直接把该区间的信息传下去.如果该区间内所有值不一样,将延迟标记扔下去. 总体难度不算大,仔细一些就能AC. 不过这样的方法是水过去的. 10W个2 3 2 3 2 3 2 3..... 10W次操作 +6 s

hdu5828 Rikka with Sequence

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5828 [题解] 考虑bzoj3211 花神游历各国,只是多了区间加操作. 考虑上题写法,区间全为1打标记.考虑推广到这题:如果一个区间max开根和min开根相同,区间覆盖标记. 巧的是,这样复杂度是错的! e.g: $n = 10^5, m = 10^5$ $a[] = \{1, 2, 1, 2, ... , 1, 2\}$ $operation = \{ "1~1~n~2", "