您的位置:首页 > 产品设计 > UI/UE

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: