题解 P2801 【教主的魔法】
EightSixSun · · 题解
不知道为什么上面说这题线段树做不了啊
看了这题一眼线段树,正好还是qbxt不确定能不能用线段树+lazy做的那种问题,然后做了做,线段树确实可做啊
总的思路就是:
维护区间min
修改就是区间修改+lazy标记(不要忘记回推),询问的时候如果区间被询问区间包含并且最小值大于等于c,那么这段区间里的人全是身高符合要求的
我永远喜欢线段树
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
#define mid ((l+r)>>1)
#define ls (x<<1)
#define rs ((x<<1)|1)
using namespace std;
inline int read()
{
char c;
bool t=0;
int a=0;
while((c=getchar())==' '||c=='\n'||c=='\r');
if(c=='-')
{
t=1;
c=getchar();
}
while(c>='0'&&c<='9')
{
a*=10;
a+=(c-'0');
c=getchar();
}
return a*(t?-1:1);
}
int n,q,minn[4000010],lazy[4000010],ans;
void build(int l,int r,int x)
{
if(l==r)
minn[x]=read();
else
{
build(l,mid,ls);
build(mid+1,r,rs);
minn[x]=min(minn[ls],minn[rs]);
}
}
void down(int x)
{
minn[ls]+=lazy[x];
lazy[ls]+=lazy[x];
minn[rs]+=lazy[x];
lazy[rs]+=lazy[x];
lazy[x]=0;
}
void ask(int l,int r,int x,int ll,int rr,int k)
{
if(ll<=l&&r<=rr&&minn[x]>=k)
{
ans+=r-l+1;
return;
}
if(l==r)
return;
if(lazy[x])
down(x);
if(ll<=mid)
ask(l,mid,ls,ll,rr,k);
if(mid<rr)
ask(mid+1,r,rs,ll,rr,k);
}
void modify(int l,int r,int x,int ll,int rr,int k)
{
if(ll<=l&&r<=rr)
{
minn[x]+=k;
lazy[x]+=k;
return;
}
if(lazy[x])
down(x);
if(ll<=mid)
modify(l,mid,ls,ll,rr,k);
if(mid<rr)
modify(mid+1,r,rs,ll,rr,k);
minn[x]=min(minn[ls],minn[rs]);
}
int main()
{
char c;
int tx,ty,tz;
n=read();q=read();
build(1,n,1);
rep(i,1,q)
{
while((c=getchar())==' '||c=='\n'||c=='\r');
tx=read();ty=read();tz=read();
if(c=='M')
{
modify(1,n,1,tx,ty,tz);
}
else if(c=='A')
{
ans=0;
ask(1,n,1,tx,ty,tz);
printf("%d\n",ans);
}
}
return 0;
}