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的主要内容,如果未能解决你的问题,请参考以下文章