CodeVS 4927-线段树练习5

Posted HAdolf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeVS 4927-线段树练习5相关的知识,希望对你有一定的参考价值。

题目&之前写过的题解

题解

  这是我第二次写这道题了,也是我转语言之后写的第一次。

  首先要明确一点,不让一个节点同时拥有两个懒标记(delta,set),并且set的优先级比delta大,接着就好办了。

  于是你会发现,每个子程序的第一句话都是下传set标记。每次下传都要将该点的sum/max/min值计算一遍。

代码:

#include<cmath>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#define INF 10000000
#define ll long long
using namespace std;

ll n,m,x,y,z;
char ch[5];
struct poi{int l,r;ll sum,delta,set,max,min;bool bn;} a[800010];

ll calcsum(int x) {return a[x].bn? a[x].set*(a[x].r-a[x].l+1):a[x].sum+a[x].delta*(a[x].r-a[x].l+1);}
ll calcmax(int x) {return a[x].bn? a[x].set:a[x].max+a[x].delta;}
ll calcmin(int x) {return a[x].bn? a[x].set:a[x].min+a[x].delta;}
void calc(int x)
{
	a[x].sum=calcsum(x<<1)+calcsum(x<<1|1);
	a[x].max=max(calcmax(x<<1),calcmax(x<<1|1));
	a[x].min=min(calcmin(x<<1),calcmin(x<<1|1));
}

void pushdownset(int x)
{
	a[x<<1].bn=a[x<<1|1].bn=1;a[x<<1].set=a[x<<1|1].set=a[x].set;a[x<<1].delta=a[x<<1|1].delta=0;
	a[x].sum=calcsum(x);a[x].max=calcmax(x);a[x].min=calcmin(x);a[x].bn=0;
}
void pushdowndelta(int x)
{
	if (a[x<<1].bn) pushdownset(x<<1);if (a[x<<1|1].bn) pushdownset(x<<1|1);
	a[x<<1].delta+=a[x].delta;a[x<<1|1].delta+=a[x].delta;
	a[x].sum=calcsum(x);a[x].max=calcmax(x);a[x].min=calcmin(x);a[x].delta=0;
}

void build(int x,int l,int r)
{
	a[x].l=l; a[x].r=r;
	if (l==r) {scanf("%lld",&a[x].sum); a[x].max=a[x].min=a[x].sum; return;}
	build(x<<1,l,(l+r)>>1); build(x<<1|1,((l+r)>>1)+1,r);
	calc(x);
}

void delta(int x,int l,int r,ll del)
{
	if (a[x].bn) pushdownset(x);
	if (a[x].l>=l && a[x].r<=r) {a[x].delta+=del; return;}
	if (a[x].delta) pushdowndelta(x);
	if (l<=(a[x].l+a[x].r)>>1) delta(x<<1,l,r,del);
	if (r>(a[x].l+a[x].r)>>1) delta(x<<1|1,l,r,del);
	calc(x);
}

void set(int x,int l,int r,ll s)
{
	if (a[x].bn) pushdownset(x);
	if (a[x].l>=l && a[x].r<=r) {a[x].bn=1; a[x].set=s; a[x].delta=0; return;}
	if (a[x].delta) pushdowndelta(x);
	if (l<=(a[x].l+a[x].r)>>1) set(x<<1,l,r,s);
	if (r>(a[x].l+a[x].r)>>1) set(x<<1|1,l,r,s);
	calc(x);
}

ll querysum(int x,int l,int r)
{
	ll ret=0;
	if (a[x].bn) pushdownset(x);
	if (a[x].l>=l && a[x].r<=r) return calcsum(x);
	if (a[x].delta) pushdowndelta(x);
	if (l<=(a[x].l+a[x].r)>>1) ret+=querysum(x<<1,l,r);
	if (r>(a[x].l+a[x].r)>>1) ret+=querysum(x<<1|1,l,r);
	return ret;
}

ll querymax(int x,int l,int r)
{
	ll ret=-INF;
	if (a[x].bn) pushdownset(x);
	if (a[x].l>=l && a[x].r<=r) return calcmax(x);
	if (a[x].delta) pushdowndelta(x);
	if (l<=(a[x].l+a[x].r)>>1) ret=max(ret,querymax(x<<1,l,r));
	if (r>(a[x].l+a[x].r)>>1) ret=max(ret,querymax(x<<1|1,l,r));
	return ret;
}

ll querymin(int x,int l,int r)
{
	ll ret=INF;
	if (a[x].bn) pushdownset(x);
	if (a[x].l>=l && a[x].r<=r) return calcmin(x);
	if (a[x].delta) pushdowndelta(x);
	if (l<=(a[x].l+a[x].r)>>1) ret=min(ret,querymin(x<<1,l,r));
	if (r>(a[x].l+a[x].r)>>1) ret=min(ret,querymin(x<<1|1,l,r));
	return ret;
}

main()
{
	scanf("%lld%lld",&n,&m);
    build(1,1,n);
    for (int i=1; i<=m; i++)
    {
        scanf("%s",ch);
        if (ch[0]==\'a\') {scanf("%lld%lld%lld",&x,&y,&z); delta(1,x,y,z);}
        if (ch[1]==\'e\') {scanf("%lld%lld%lld",&x,&y,&z); set(1,x,y,z);}
        if (ch[1]==\'u\') {scanf("%lld%lld",&x,&y); printf("%lld\\n",querysum(1,x,y));}
        if (ch[1]==\'a\') {scanf("%lld%lld",&x,&y); printf("%lld\\n",querymax(1,x,y));}
        if (ch[1]==\'i\') {scanf("%lld%lld",&x,&y); printf("%lld\\n",querymin(1,x,y));}
    }
    return 0;
}

 

以上是关于CodeVS 4927-线段树练习5的主要内容,如果未能解决你的问题,请参考以下文章

CodeVS 4927-线段树练习5

codevs 4927 线段树练习5 线段树基本操作模板

codevs 4927 线段树练习5

codevs 4927 线段树练习5

分块试水--CODEVS4927 线段树练习5

线段树练习5(codevs 4927)