hdu5828 Rikka with Sequence(线段树)

思路:HDU4027的升级版,多了一个区间add的操作,考虑一下显然开根号的递减速度是很快的,2^64最多不超过8次就能减到1,而且会出现很多区间的数字都是一样的情况,那么可以在线段树多维护一个flag值,表示区间里面是否所有数都是相等的,如果是的话那么开根号就只开到这里就行了,具体实现细节还是蛮多的....


后来HDU加数据了,比如2 3 2 3 2 3然后整体加6然后开根号,又会变回2 3 2 3 2 3相当于不会出现区间数字一样的情况了,这样就相当于没剪枝,变成了n^2...后来发现只有极差为1的时候才会出现这种情况,极差>1的话是不可能维持原来的序列的,那么就可以维护一个最大值和最小值,如果极差为1的话那么区间开根号其实相当于区间减去了x-sqrt(x),再加上第一个版本的剪枝就可以2000MS左右过去了

第一版本(TLE):

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000+50;
#define LL long long
#define eps 1e-8
#define LL long long
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
LL sum[maxn<<2],lazy[maxn<<2],flag[maxn<<2];

void push_up(int i)
{
    sum[i]=sum[i<<1]+sum[i<<1|1];
	if(flag[i<<1]==flag[i<<1|1])
		flag[i]=flag[i<<1];
	else
		flag[i]=0;
}
void pushdown(int r,int m)
{
     if(flag[r])
	 {
		 flag[r<<1]=flag[r];
		 flag[r<<1|1]=flag[r];
		 sum[r<<1]=flag[r]*(m-m/2);
		 sum[r<<1|1]=flag[r]*(m/2);
		 lazy[r]=0;
	 }
	 if(lazy[r])
	 {
		 lazy[r<<1]+=lazy[r];
		 lazy[r<<1|1]+=lazy[r];
		 if(flag[r<<1])
			 flag[r<<1]+=lazy[r];
		 if(flag[r<<1|1])
			 flag[r<<1|1]+=lazy[r];
		 sum[r<<1]+=lazy[r]*(m-m/2);
		 sum[r<<1|1]+=lazy[r]*(m/2);
		 lazy[r]=0;
	 }
}
void build(int i,int l,int r)
{
     lazy[i]=0;
	 flag[i]=0;
	 if(l==r)
	 {
		 scanf("%d",&sum[i]);
		 flag[i]=sum[i];
		 return;
	 }
	 int mid = (l+r)>>1;
	 build(lson);
	 build(rson);
	 push_up(i);
}

void update(int ql,int qr,int v,int i,int l,int r)
{
     if(ql<=l && qr>=r)
	 {
		 sum[i]+=1LL*(r-l+1)*v;
		 lazy[i]+=v;
		 if(flag[i])
			 flag[i]+=v;
		 return;
	 }
	 pushdown(i,r-l+1);
	 int mid = (l+r)>>1;
	 if(ql<=mid)
		 update(ql,qr,v,lson);
	 if(qr>mid)
		 update(ql,qr,v,rson);
	 push_up(i);
}

void update1(int ql,int qr,int i,int l,int r)
{
     if(ql<=l && qr>=r && flag[i])
	 {
		 flag[i]=(sqrt(flag[i])+eps);
		 sum[i]=1LL*flag[i]*(r-l+1);
		 return;
	 }
	 pushdown(i,r-l+1);
	 int mid = (l+r)>>1;
	 if(ql<=mid)
		 update1(ql,qr,lson);
	 if(qr>mid)
		 update1(ql,qr,rson);
	 push_up(i);
}
LL query(int ql,int qr,int i,int l,int r)
{
    if(ql<=l && qr>=r)
		return sum[i];
	pushdown(i,r-l+1);
	int mid = (l+r)>>1;
	LL ans = 0;
	if(ql<=mid)
		ans+=query(ql,qr,lson);
	if(mid<qr)
		ans+=query(ql,qr,rson);
	return ans;
}

int main()
{
    int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,q;
		scanf("%d%d",&n,&q);
		build(1,1,n);
		while(q--)
		{
			int x,y,w,op;
			scanf("%d",&op);
			if(op==1)
			{
				scanf("%d%d%d",&x,&y,&w);
				update(x,y,w,1,1,n);
			}
			if(op==2)
			{
				scanf("%d%d",&x,&y);
				update1(x,y,1,1,n);
			}
			if(op==3)
			{
				scanf("%d%d",&x,&y);
				printf("%lld\n",query(x,y,1,1,n));
			}
		}
	}
}


更新版:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000+50;
#define LL long long
#define eps 1e-8
#define LL long long
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
LL sum[maxn<<2],lazy[maxn<<2],maxx[maxn<<2],minn[maxn<<2];
const int read()
{
	char ch = getchar();
	while (ch<'0' || ch>'9') ch = getchar();
	int x = ch - '0';
	while ((ch = getchar()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';
	return x;
}

void push_up(int i)
{
	maxx[i]=max(maxx[i<<1],maxx[i<<1|1]);
	minn[i]=min(minn[i<<1],minn[i<<1|1]);
    sum[i]=sum[i<<1]+sum[i<<1|1];
}
void pushdown(int r,int m)
{
	 if(lazy[r])
	 {
		 lazy[r<<1]+=lazy[r];
		 maxx[r<<1]+=lazy[r];
		 maxx[r<<1|1]+=lazy[r];
		 minn[r<<1]+=lazy[r];
		 minn[r<<1|1]+=lazy[r];
		 lazy[r<<1|1]+=lazy[r];
		 sum[r<<1]+=lazy[r]*(m-m/2);
		 sum[r<<1|1]+=lazy[r]*(m/2);
		 lazy[r]=0;
	 }     
     if(minn[r]==maxx[r])
	 {
		 minn[r<<1]=maxx[r<<1]=minn[r<<1|1]=maxx[r<<1|1]=minn[r];
		 sum[r<<1]=minn[r]*(m-m/2);
		 sum[r<<1|1]=maxx[r]*(m/2);
	 }
}
void build(int i,int l,int r)
{
     lazy[i]=0;
	 if(l==r)
	 {
		 scanf("%d",&sum[i]);
		 minn[i]=sum[i];
		 maxx[i]=sum[i];
		 return;
	 }
	 int mid = (l+r)>>1;
	 build(lson);
	 build(rson);
	 push_up(i);
}

void update(int ql,int qr,int v,int i,int l,int r)
{
     if(ql<=l && qr>=r)
	 {
		 minn[i]+=v;
		 maxx[i]+=v;
		 sum[i]+=1LL*(r-l+1)*v;
		 lazy[i]+=v;
		 return;
	 }
	 pushdown(i,r-l+1);
	 int mid = (l+r)>>1;
	 if(ql<=mid)
		 update(ql,qr,v,lson);
	 if(qr>mid)
		 update(ql,qr,v,rson);
	 push_up(i);
}

void update1(int ql,int qr,int i,int l,int r)
{
     if(ql<=l && qr>=r)
	 {
		 if((int)sqrt(minn[i]) == (int)sqrt(maxx[i]))
		 {
			 minn[i]=maxx[i]=(int)sqrt(minn[i]);
			 sum[i]=minn[i]*(r-l+1);
		 }
		 else if(minn[i]+1==maxx[i])
		 {
			 int k = maxx[i]-(int)sqrt(maxx[i]);
			 update(ql,qr,-k,i,l,r);
		 }
		 else
		 {
	         pushdown(i,r-l+1);
			 int mid = (l+r)>>1;
			 if(ql<=mid)update1(ql,qr,lson);
			 if(qr>mid)update1(ql,qr,rson);
			 push_up(i);
		 }
		 return;
	 }
	 pushdown(i,r-l+1);
	 int mid = (l+r)>>1;
	 if(ql<=mid)
		 update1(ql,qr,lson);
	 if(qr>mid)
		 update1(ql,qr,rson);
	 push_up(i);
}
LL query(int ql,int qr,int i,int l,int r)
{
    if(ql<=l && qr>=r)
		return sum[i];
	pushdown(i,r-l+1);
	int mid = (l+r)>>1;
	LL ans = 0;
	if(ql<=mid)
		ans+=query(ql,qr,lson);
	if(mid<qr)
		ans+=query(ql,qr,rson);
	return ans;
}

int main()
{
    int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,q;
		scanf("%d%d",&n,&q);
	//	n = Scan();
	//	q = Scan();
		build(1,1,n);
		while(q--)
		{
			int x,y,w,op;
			scanf("%d",&op);
			if(op==1)
			{
				scanf("%d%d%d",&x,&y,&w);
			//	x = Scan();
			//	y = Scan();
			//	w = Scan();
				update(x,y,w,1,1,n);
			}
			if(op==2)
			{
				scanf("%d%d",&x,&y);
			//	x = Scan();
			//	y = Scan();
				update1(x,y,1,1,n);
			}
			if(op==3)
			{
				scanf("%d%d",&x,&y);
			//	x = Scan();
			//	y = Scan();
				printf("%lld\n",query(x,y,1,1,n));
			}
		}
	}
}


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 makes m operations on it. 

There are three type of operations:

1 l r x : For each i in [l,r], change A[i] to A[i]+x
2 l r : For each i in [l,r], change A[i] to  A[i]
3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]

It is too difficult for Rikka. Can you help her?
 

Input
The first line contains a number t(1<=t<=100), the number of the testcases. And there are no more than 5 testcases with n>1000.

For each testcase, the first line contains two numbers n,m(1<=n,m<=100000). The second line contains n numbers A[1]~A[n]. Then m lines follow, each line describe an operation.

It is guaranteed that 1<=A[i],x<=100000.
 

Output
For each operation of type 3, print a lines contains one number -- the answer of the query.
 

Sample Input
  
  
1 5 5 1 2 3 4 5 1 3 5 2 2 1 4 3 2 4 2 3 5 3 1 5
 

Sample Output
  
  
5 6
 

Author
学军中学
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值