卧薪尝胆,厚积薄发。
Play with sequence
Date: Fri Feb 15 19:16:42 CST 2019 In Category: NoCategory

Description:

给一个数列,要求支持区间赋值,区间加并对 $0$ 取 $\max$ ,询问区间 $0$ 的个数。
$1\leqslant n\leqslant 300000$

Solution:

首先既然任意时刻所有数都大于等于零,那么第三个操作就可以看成是询问区间最小值的个数,看到取 $\max$ 就可以想到吉司机线段树,正好维护了区间最小值个数于是又是模板题了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 300010
typedef long long ll;
ll a[MAXN];
#define INF 0x3f3f3f3f3f3f3f3f
struct node
{
int lc,rc,siz;
ll fi,se,cnt,tag,add,set;
}t[MAXN << 1];
int ptr = 0;
int newnode(){return ++ptr;}
int root;
#define mid ((l + r) >> 1)
void pushup(int rt)
{
int lc = t[rt].lc,rc = t[rt].rc;
ll lv = t[lc].fi,rv = t[rc].fi;
if(lv == rv){t[rt].fi = lv;t[rt].cnt = t[lc].cnt + t[rc].cnt;t[rt].se = min(t[lc].se,t[rc].se);}
else if(lv < rv){t[rt].fi = lv;t[rt].cnt = t[lc].cnt;t[rt].se = min(t[lc].se,t[rc].fi);}
else if(lv > rv){t[rt].fi = rv;t[rt].cnt = t[rc].cnt;t[rt].se = min(t[lc].fi,t[rc].se);}
return;
}
void tagset(int rt,ll val)
{
t[rt].set = val;t[rt].cnt = t[rt].siz;t[rt].se = INF;t[rt].fi = val;
t[rt].tag = -INF;t[rt].add = 0;
return;
}
void tagadd(int rt,ll val)
{
if(t[rt].se != INF)t[rt].se += val;
if(t[rt].tag != -INF)t[rt].tag += val;
t[rt].fi += val;t[rt].add += val;
return;
}
void tagmax(int rt,ll val)
{
t[rt].fi = max(t[rt].fi,val);
t[rt].tag = max(t[rt].tag,val);
return;
}
void pushdown(int rt)
{
if(t[rt].set != INF)tagset(t[rt].lc,t[rt].set),tagset(t[rt].rc,t[rt].set),t[rt].set = INF;
if(t[rt].add != 0)tagadd(t[rt].lc,t[rt].add),tagadd(t[rt].rc,t[rt].add),t[rt].add = 0;
if(t[rt].tag != -INF)tagmax(t[rt].lc,t[rt].tag),tagmax(t[rt].rc,t[rt].tag),t[rt].tag = -INF;
return;
}
void build(int &rt,int l,int r)
{
rt = newnode();
t[rt].siz = r - l + 1;t[rt].tag = -INF;t[rt].se = t[rt].set = INF;t[rt].add = 0;
if(l == r)
{
t[rt].fi = a[l];t[rt].cnt = 1;
return;
}
build(t[rt].lc,l,mid);build(t[rt].rc,mid + 1,r);
pushup(rt);
return;
}
void set(int rt,int L,int R,ll k,int l,int r)
{
if(L <= l && r <= R){tagset(rt,k);return;}
pushdown(rt);
if(L <= mid)set(t[rt].lc,L,R,k,l,mid);
if(R > mid)set(t[rt].rc,L,R,k,mid + 1,r);
pushup(rt);
return;
}
void add(int rt,int L,int R,ll k,int l,int r)
{
if(L <= l && r <= R){tagadd(rt,k);return;}
pushdown(rt);
if(L <= mid)add(t[rt].lc,L,R,k,l,mid);
if(R > mid)add(t[rt].rc,L,R,k,mid + 1,r);
pushup(rt);
return;
}
void tag(int rt,int L,int R,ll k,int l,int r)
{
if(L <= l && r <= R)
{
if(k <= t[rt].fi)return;
if(t[rt].se > k)
{
tagmax(rt,k);
return;
}
}
pushdown(rt);
if(L <= mid)tag(t[rt].lc,L,R,k,l,mid);
if(R > mid)tag(t[rt].rc,L,R,k,mid + 1,r);
pushup(rt);
return;
}
ll query(int rt,int L,int R,int l,int r)
{
if(L <= l && r <= R)return (t[rt].fi == 0 ? t[rt].cnt : 0);
ll res = 0;
pushdown(rt);
if(L <= mid)res += query(t[rt].lc,L,R,l,mid);
if(R > mid)res += query(t[rt].rc,L,R,mid + 1,r);
return res;
}
int main()
{
//freopen("kkk.in","r",stdin);
//freopen("kkk.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)scanf("%lld",&a[i]);
build(root,1,n);
int opt,l,r;
ll k;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&opt,&l,&r);
if(opt == 1){scanf("%lld",&k);set(root,l,r,k,1,n);}
if(opt == 2){scanf("%lld",&k);add(root,l,r,k,1,n);tag(root,l,r,0,1,n);}
if(opt == 3)printf("%lld\n",query(root,l,r,1,n));
}
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡