UOJ228 基础数据结构练习题

Posted ljh2000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UOJ228 基础数据结构练习题相关的知识,希望对你有一定的参考价值。

本文作者:ljh2000 
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

题目链接:http://uoj.ac/problem/228

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

 

 

 

正解:线段树

解题报告:

  这道题是一道线段树的神题,需要我们支持区间开方、区间加法和区间求和操作。

  关键是对于开方操作的处理,考虑如果一个区间最大值等于最小值(即全都相等),那么就可以直接开方,然后区间赋值。

  否则就往下递归处理,知道发现整个区间相等再区间操作。

  上述做法在这样的数据下会被卡TLE:8、9、8、9,这样每次都会达到最坏复杂度。

  但是我们发现他们如果开方之后的减少的值是相同的,也就是说这种情况我们可以特判,变成区间减法操作,这样就可以保证复杂度。

  为了降低编程复杂度,可以把区间赋值操作变成区间减法,也就是负数的区间减法,会方便很多。

  另外,标记可持久化+不下传,可以大大减小常数。

 

//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <complex>
#define lc root<<1
#define rc root<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 100011;
int n,m,c[MAXN],ql,qr,val;
LL ans;
struct node{ int l,r,len; LL sum,Max,Min,tag; }a[MAXN*3];
inline void jia(node &tmp,LL y){ tmp.tag+=y; tmp.Min+=y; tmp.Max+=y; tmp.sum+=tmp.len*y; }
inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<\'0\'||c>\'9\') && c!=\'-\') c=getchar();
    if(c==\'-\') q=1,c=getchar(); while (c>=\'0\'&&c<=\'9\') w=w*10+c-\'0\',c=getchar(); return q?-w:w;
}

inline void update(int root){
	a[root].sum=a[lc].sum+a[rc].sum+a[root].tag*a[root].len;
	a[root].Max=max(a[lc].Max,a[rc].Max); a[root].Max+=a[root].tag;
	a[root].Min=min(a[lc].Min,a[rc].Min); a[root].Min+=a[root].tag;
}

inline void build(int root,int l,int r){
	a[root].l=l; a[root].r=r; a[root].len=r-l+1;
	if(l==r) { a[root].Max=a[root].Min=a[root].sum=c[l]; return ; }
	int mid=(l+r)>>1; 
	build(lc,l,mid);
	build(rc,mid+1,r);
	update(root);
}

inline void add(int root,int l,int r){
	if(ql<=l && r<=qr) {
		jia(a[root],val);
		return ;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) add(root<<1,l,mid);
	if(qr>mid) add(root<<1|1,mid+1,r);
	update(root);
}

inline void Sqr(int root,int l,int r,LL tag){
	if(ql<=l && r<=qr) {
		LL cp1,cp2; cp1=(LL)sqrt(a[root].Min+tag)+1; cp2=(LL)sqrt(a[root].Max+tag);//注意比较对象...
		LL cha;//long long!!!
		if(a[root].Max==a[root].Min){
			cha=(a[root].Min+tag)-(LL)sqrt(a[root].Min+tag);
			jia(a[root],-cha);
			return ;
		}
		else if((a[root].Max==a[root].Min+1) && cp1==cp2) {//实数相等用eps!!!
			cha=(a[root].Min+tag)-(LL)(sqrt(a[root].Min+tag));//没有+1啊...
			jia(a[root],-cha);
			return ;
		}
	}
	int mid=(l+r)>>1;
	if(ql<=mid) Sqr(lc,l,mid,tag+a[root].tag);
	if(qr>mid) Sqr(rc,mid+1,r,tag+a[root].tag);
	update(root);
}

inline void query(int root,int l,int r,LL tag){
	if(ql<=l && r<=qr) {
		ans+=a[root].sum+tag*a[root].len;
		return ;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) query(lc,l,mid,tag+a[root].tag);
	if(qr>mid) query(rc,mid+1,r,tag+a[root].tag);
}

inline void work(){
	n=getint(); m=getint(); for(int i=1;i<=n;i++) c[i]=getint(); 
	int type; build(1,1,n);
	while(m--) {
		type=getint();
		if(type==1) {
			ql=getint(); qr=getint(); val=getint();
			add(1,1,n);
		}
		else if(type==2) {
			ql=getint(); qr=getint();
			Sqr(1,1,n,0);
		}
		else{
			ql=getint(); qr=getint(); ans=0;
			query(1,1,n,0);
			printf("%lld\\n",ans);
		}
	}
}

int main()
{
    work();
    return 0;
}

  

以上是关于UOJ228 基础数据结构练习题的主要内容,如果未能解决你的问题,请参考以下文章

uoj228 基础数据结构练习题

[UOJ228] 基础数据结构练习题 - 线段树

UOJ - #228. 基础数据结构练习题

UOJ#228. 基础数据结构练习题

线段树uoj#228. 基础数据结构练习题

uoj#228. 基础数据结构练习题(线段树)