2016多校8 HDU 5828 Rikka with Sequence 线段树优化
2016-08-13 03:08
429 查看
2016多校联合训练#8
HDU 5828 Rikka with Sequence
线段树优化,想法
传送门:HDU题意
很明确是线段树,需要三种操作:区间更新(加值),区间开根号,区间求和。区间开根号就是区间内部每一个值开根号。思路
先膜吧:我和这个大佬的代码风格很像,所以看的很舒服,大佬思路也很详细清晰,适合我这种咸鱼看。膜膜膜。区间更新和求和直接套线段树板子,问题就在于区间开跟。开跟没有什么特别好的性质,首先想到的是朴素O(n)开跟,必T。开始优化。
额外再保存区间内部最大值与最小值。如果最大值是1,那么直接return,1开跟没卵用。这个优化比较有用,因为100000开4~5次跟就是1了,一个数老被开跟。。。啥也不剩了。
保存了区间最大最小值,那么如果区间最大值等于最小值,说明区间内所有值是一样的。那么可以变成区间加法操作。lazy+=(sqrt(data[rt])-data[rt])。
接下来的优化就很神奇了。。大佬说:
在昨天数据加强了以后,看到ACFun群里糖老师随手出了个数据卡掉了大部分人的程序,就是我之前的那个。
比如说:2 3 2 3 2 3这样10万个数字。然后10万次操作,(整体+6,整体sqrt)。
这个数据,我之前的程序要跑好几分钟,因为每个相邻的数字都不一样,而且整体加了以后,开方以后还是保持这样的情况,也就是说,每次操作以后,不能找到整段相等的情况。这样的话,就会一直更新下去,就非常慢。
这种情况只可能出现在max-min==1的情况。这样的区间开跟结果有两种,要么开跟后区间最大值最小值相等了。这样的需要加一个类似lazy的标记cover,优先级比lazy高。因为这个标记可以存区间值到底应该是多少,如果pushdown时这个值不是0,直接更新节点。另一个结果是开跟后区间极差仍然是1。这样相当于区间全减去一个值。用区间加做就可以了。
至于大佬说的输入挂,我在HDU上交了不带挂的,也过了。所以不知道怎么回事。
代码
输入挂加不加貌似都能过,自己试试吧#include <iostream> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cstring> #include <cmath> #include <vector> #include <queue> #include <stack> #include <iomanip> #include <string> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int MAXN=100005; typedef long long int LL; template <class T> inline void rd(T &x){ char c=getchar(); x=0;while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } struct Tree{ LL data=0; LL lazy=0; LL ma=0; LL mi=0; LL manum=0; LL minum=0; LL cover=0; }sum[MAXN<<2];//线段树 inline void PushUp(int rt) { sum[rt].data=sum[rt<<1].data+sum[rt<<1|1].data; sum[rt].ma=max(sum[rt<<1].ma,sum[rt<<1|1].ma); sum[rt].mi=min(sum[rt<<1].mi,sum[rt<<1|1].mi); sum[rt].manum=sum[rt].minum=0; if(sum[rt].ma==sum[rt<<1].ma) sum[rt].manum+=sum[rt<<1].manum; if(sum[rt].ma==sum[rt<<1|1].ma) sum[rt].manum+=sum[rt<<1|1].manum; if(sum[rt].mi==sum[rt<<1].mi) sum[rt].minum+=sum[rt<<1].minum; if(sum[rt].mi==sum[rt<<1|1].mi) sum[rt].minum+=sum[rt<<1|1].minum; } inline void PushDown(int rt,int m) { if(sum[rt].cover!=0){ sum[rt<<1].cover=sum[rt<<1|1].cover=sum[rt].cover; sum[rt<<1].data=(LL) sum[rt].cover*(m-(m>>1)); sum[rt<<1|1].data=(LL) sum[rt].cover*(m>>1); sum[rt<<1].ma=sum[rt<<1|1].ma=sum[rt<<1].mi=sum[rt<<1|1].mi=sum[rt].cover; sum[rt<<1].manum=sum[rt<<1].minum=(m-(m>>1)); sum[rt<<1|1].manum=sum[rt<<1|1].minum=(m>>1); sum[rt<<1].lazy=sum[rt<<1|1].lazy=0; sum[rt].cover=0; } if(sum[rt].lazy!=0) { sum[rt<<1].lazy+=sum[rt].lazy; sum[rt<<1|1].lazy+=sum[rt].lazy; sum[rt<<1].data+=(sum[rt].lazy)*(m-(m>>1)); sum[rt<<1|1].data+=(sum[rt].lazy)*(m>>1); sum[rt<<1].ma+=sum[rt].lazy; sum[rt<<1].mi+=sum[rt].lazy; sum[rt<<1|1].ma+=sum[rt].lazy; sum[rt<<1|1].mi+=sum[rt].lazy; sum[rt].lazy=0; } } inline void build(int l,int r,int rt) { sum[rt].lazy=sum[rt].manum=sum[rt].minum=sum[rt].cover=0; if(l==r) { scanf("%lld",&(sum[rt].data)); //rd(sum[rt].data); sum[rt].ma=sum[rt].data; sum[rt].mi=sum[rt].data; sum[rt].manum=sum[rt].minum=1; return; } int m=(l+r)>>1; build(lson); build(rson); PushUp(rt); } inline void update(int L,int R,int c,int l,int r,int rt) { if(L<=l && r<=R) { sum[rt].lazy+=c; sum[rt].data+=(LL)c*(r-l+1); sum[rt].ma+=c; sum[rt].mi+=c; return; } PushDown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(L,R,c,lson); if(m<R) update(L,R,c,rson); PushUp(rt); } inline void update_s(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { if(sum[rt].ma==1) return; if(l==r) { sum[rt].data=floor(sqrt(sum[rt].data)); sum[rt].ma=sum[rt].data; sum[rt].mi=sum[rt].data; return; } if(sum[rt].ma==sum[rt].mi) { LL temp=sum[rt].ma; sum[rt].ma=floor(sqrt(temp)); sum[rt].mi=floor(sqrt(temp)); sum[rt].data=(LL)sum[rt].ma*(r-l+1); sum[rt].lazy+=(sum[rt].ma-temp); return; } else if(sum[rt].ma-sum[rt].mi==1) { LL temp=sum[rt].ma; sum[rt].ma=floor(sqrt(sum[rt].ma)); sum[rt].mi=floor(sqrt(sum[rt].mi)); if(sum[rt].ma-sum[rt].mi==1) { sum[rt].lazy+=(sum[rt].ma-temp); sum[rt].data=(LL) sum[rt].ma*sum[rt].manum+(LL) sum[rt].mi*sum[rt].minum; } else { sum[rt].manum=sum[rt].minum=r-l+1; sum[rt].cover=sum[rt].ma; sum[rt].lazy=0; sum[rt].data=(LL) sum[rt].ma*(r-l+1); } return; } PushDown(rt,r-l+1); int m=(l+r)>>1; update_s(L,R,lson); update_s(L,R,rson); PushUp(rt); return; } PushDown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update_s(L,R,lson); if(m<R) update_s(L,R,rson); PushUp(rt); } inline LL query(int L,int R,int l,int r,int rt) { if(L<=l && r<=R) { return sum[rt].data; } PushDown(rt,r-l+1); int m=(l+r)>>1; LL ret=0; if(L<=m) ret+=query(L,R,lson); if(m<R) ret+=query(L,R,rson); return ret; } int main() { //freopen("1008.in","r",stdin); //freopen("out.out","w",stdout); int T; scanf("%d",&T); while(T--) { int m,n; scanf("%d%d",&n,&m); build(1,n,1); int s,l,r; while(m--) { scanf("%d%d%d",&s,&l,&r); if(s==1) { int x; scanf("%d",&x); update(l,r,x,1,n,1); } else if(s==2) { update_s(l,r,1,n,1); } else { LL res=query(l,r,1,n,1); printf("%lld\n",res); } } } return 0; }
相关文章推荐
- HDU 5828 Rikka with Sequence(线段树+小优化)
- hdu 5828 Rikka with Sequence 线段树
- HDU 5828 Rikka with Sequence
- HDU 5828 Rikka with Sequence(线段树)
- HDU 5828-H - Rikka with Sequence-线段树+玄学-区间开方/区间更新/区间求和
- hdu 5828 2016 Multi-University Training Contest 8 Rikka with Sequence 解题报告
- Hdu 5828 Rikka with Sequence
- hdu 5828 Rikka with Sequence 【线段树+优化】
- HDU 5828 多校第八场 1008 Rikka with Sequence(线段树--数据加强版)
- Hdu-5828 Rikka with Sequence(线段树)
- HDU 5828 Rikka with Sequence
- HDU-5828-Rikka with Sequence(线段树)
- HDU 5828 Rikka with Sequence(线段树 开根号)
- HDU 5828 Rikka with Sequence(线段树)
- HDU 5828 Rikka with Sequence 线段树优化
- HDU 5828 Rikka with Sequence 解题报告
- HDU 5828 Rikka with Sequence (线段树+剪枝优化)
- HDU 5828 Rikka with Sequence
- hdu 5828 Rikka with Sequence 【加强版已过】
- HDU 5828 Rikka with Sequence (线段树)