列表

详情


NC20897. 瑟班守护者莎利雅与护教军

描述

「瑟班是我们的家乡,我不会让它落入孽物大军手中。」            —— 莎利雅


       瑟班守护者莎利雅领导着一支护教军。这支护教军的兵力守卫在塞班的各个角落。
       瑟班大教廷中有 n 个地点,编号为 。这 n 个地点排成一列,第 i 个地点有 di 的危险值,并有值为 fi 的兵力分布在这里。
       为了更好的应战,每个地点所分布的兵力会根据每个地点危险值的变化而变化。更形式化地,第 i 个地点的兵力值 fi 可以根据以下公式计算:
       
       特别地,当 i=1 时, 项值为 0 ;当 i=n 时, 项值也为 0 。
       现在,莎利雅作为瑟班的守护者、月主教护卫部队领袖,遇到了一些难题。她需要处理下级提供的情报,并能随时获取自己已分配的总兵力,或者了解哪些位置兵力足够、哪些位置兵力不足。
       更形式化地,我们将这一系列操作分为以下三种:
1. 莎利雅需要知道已分配的总兵力:询问所有地点的兵力值总和。即  。
2. 莎利雅需要知道某个区间内哪些位置兵力充足:编号在 [l, r] 的地点中兵力值大于等于 v 的个数。即
3. 莎利雅获得情报:地点 i 的危险值增加了 v 。由于乱战愈发激烈,每个地区的危险值不会降低。也就是说,v 是一个非负整数。
       莎利雅正忙于跟莉莲娜维斯交战,所以只好请你来帮助她了!

输入描述

第一行包含两个整数 n, m ,表示地点数及操作数。
第二行包含 n 个非负整数,第 i 个数表示初始时地点 i 的危险值。
接下去 m 行,每行若干个整数,表示一次操作。其中第一个数 op 表示操作类别。
- 当 op = 1 时,表示莎利雅得到了情报。你需要输出一个答案。
- 当 op = 2 时,后面跟着三个整数 l, r, v,表示莎利雅想知道区间 [l, r] 内哪些位置兵力值大于等于 v 。你需要输出一个答案。
- 当 op = 3 时,后面跟着两个整数 x, v,表示莎利雅获得了一个情报,地点 x 的危险值会加上 v 。

输出描述

输出若干行,每行对应一个 1 或 2 操作的答案。

示例1

输入:

4 3
10 5 9 5 
1
3 3 2
2 1 4 10

输出:

33
3

说明:

- 初始时,危险值序列 {di} 为 {10, 5, 9, 5} ,可以计算出兵力值序列 {fi} 为 {10, 9, 9, 5} 。
- 第一个操作为 1 操作,询问兵力值序列 {fi} 的和,为 10 + 9 + 9 + 5 = 33 。
- 第二个操作为 3 操作,将 3 号地点的危险值升高 2 。之后危险值序列 {di} 变为 {10, 5, 11, 5} ,可以计算出兵力值序列 {fi} 为 {10, 10, 11, 5} 。
- 第三个操作为 2 操作,询问兵力值序列 {fi} 中区间 [1, 4] 内兵力值大于等于 10 的地点个数。其中 1, 2, 3 号地点满足条件,答案为 3 。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 521ms, 内存消耗: 64344K, 提交时间: 2018-11-17 14:47:42

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pi 3.141592653589793
#define mod 998244353
#define LL long long
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define sf(x) scanf("%lld",&x)
#define sc(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)

using namespace std;

const int N = 300010;

LL f[N],d[N],mx1[N],mx2[N],n,m;
typedef pair<LL,int> P;

struct ST1
{
    #define ls i<<1
    #define rs i<<1|1

    struct node
    {
        int lpos,rpos,l,r;
        LL max;
    } T[N<<2];

    inline void push_up(int i)
    {
        T[i].max=max(T[ls].max,T[rs].max);
        T[i].lpos=T[T[ls].max>=T[rs].max?ls:rs].lpos;
        T[i].rpos=T[T[rs].max>=T[ls].max?rs:ls].rpos;
    }

    void build(int i,int l,int r)
    {
        T[i]=node{0,0,l,r,0};
        if (l==r)
        {
            T[i].lpos=T[i].rpos=l;
            T[i].max=d[l]; return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        push_up(i);
    }

    void update(int i,int pos,LL x)
    {
        if (T[i].l==T[i].r)
        {
            T[i].max+=x;
            return;
        }
        int mid=(T[i].l+T[i].r)>>1;
        if (mid>=pos) update(ls,pos,x);
        else if (mid<pos) update(rs,pos,x);
        push_up(i);
    }

    int query1(int i,int l,int r,LL x)
    {
        if (l>r||T[i].max<x) return 0;
        if (T[i].l==T[i].r) return T[i].max>=x?T[i].l:0;
        int mid=(T[i].l+T[i].r)>>1,res=0;
        if (l<=mid) res=query1(ls,l,r,x);
        if (r>mid&&!res) res=query1(rs,l,r,x);
        return res;
    }

    int query2(int i,int l,int r,LL x)
    {
        if (l>r||T[i].max<x) return 0;
        if (T[i].l==T[i].r) return T[i].max>=x?T[i].l:0;
        int mid=(T[i].l+T[i].r)>>1,res=0;
        if (r>mid&&!res) res=query2(rs,l,r,x);
        if (l<=mid&&!res) res=query2(ls,l,r,x);
        return res;
    }

    P getmax1(int i,int l,int r)
    {
        if (l<=T[i].l&&T[i].r<=r) return P(T[i].max,T[i].lpos);
        int mid=(T[i].l+T[i].r)>>1; P res={0,0};
        if (l<=mid) res=getmax1(ls,l,r);
        if (r>mid)
        {
            P tmp=getmax1(rs,l,r);
            if (tmp.first>res.first) res=tmp;
        }
        return res;
    }

    P getmax2(int i,int l,int r)
    {
        if (l<=T[i].l&&T[i].r<=r) return P(T[i].max,T[i].rpos);
        int mid=(T[i].l+T[i].r)>>1; P res={0,0};
        if (r>mid) res=getmax2(rs,l,r);
        if (l<=mid)
        {
            P tmp=getmax2(ls,l,r);
            if (tmp.first>res.first) res=tmp;
        }
        return res;
    }

} seg1;

struct ST2
{
    #define ls i<<1
    #define rs i<<1|1

    struct node
    {
        LL lazy,sum;
        int l,r;
    } T[N<<2];

    void build(int i,int l,int r)
    {
        T[i]=node{0,0,l,r};
        if (l==r)
        {
            T[i].sum=f[l];
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        T[i].sum=T[ls].sum+T[rs].sum;
    }

    inline void push_down(int i)
    {
        LL lazy=T[i].lazy;
        T[ls].lazy=lazy; T[rs].lazy=lazy;
        T[ls].sum=(T[ls].r-T[ls].l+1)*lazy;
        T[rs].sum=(T[rs].r-T[rs].l+1)*lazy;
        T[i].lazy=0;
    }

    void update(int i,int l,int r,LL x)
    {
        if (l>r) return;
        if (T[i].l==l&&T[i].r==r)
        {
            T[i].sum=(T[i].r-T[i].l+1)*x;
            T[i].lazy=x; return;
        }
        if (T[i].lazy) push_down(i);
        int mid=(T[i].l+T[i].r)>>1;
        if (mid>=r) update(ls,l,r,x);
        else if (mid<l) update(rs,l,r,x);
        else
        {
            update(ls,l,mid,x);
            update(rs,mid+1,r,x);
        }
        T[i].sum=T[ls].sum+T[rs].sum;
    }

} seg2;


int main()
{
    sf(n); sf(m);
    for(int i=1;i<=n;i++) sf(d[i]);
    seg1.build(1,1,n);
    for(int i=1;i<=n;i++)
        mx1[i]=max(mx1[i-1],d[i]);
    for(int i=n;i>=1;i--)
        mx2[i]=max(mx2[i+1],d[i]);
    for(int i=1;i<=n;i++)
        f[i]=max(d[i],min(mx1[i-1],mx2[i+1]));
    seg2.build(1,1,n);
    while(m--)
    {
        LL op,l,r,v;
        sf(op);
        if (op==1) printf("%lld\n",seg2.T[1].sum);
        else if (op==2)
        {
            sc(l,r,v);
            int ll=seg1.query1(1,1,l-1,v);
            int rr=seg1.query2(1,r+1,n,v);
            if (ll) ll=l; else ll=seg1.query1(1,l,r,v);
            if (rr) rr=r; else rr=seg1.query2(1,l,r,v);
            if (ll*rr==0) puts("0"); else printf("%d\n",rr-ll+1);
        } else
        {
            sf(l); sf(v);
            seg1.update(1,l,v); d[l]+=v;
            int ll=seg1.query2(1,1,l-1,d[l]);
            int rr=seg1.query1(1,l+1,n,d[l]);
            if (ll&&rr) continue;
            seg2.update(1,l,l,d[l]);
            if (ll) seg2.update(1,ll+1,l-1,d[l]);
            else if (l!=1)
            {
                P tmp=seg1.getmax2(1,1,l-1);
                seg2.update(1,tmp.second,l-1,tmp.first);
            }
            if (rr) seg2.update(1,l+1,rr-1,d[l]);
            else if (l!=1)
            {
                P tmp=seg1.getmax1(1,l+1,n);
                seg2.update(1,l+1,tmp.second,tmp.first);
            }
        }
    }
    return 0;
}
/*
5 100
1 2 3 4 5
2 1 5 4
3 2 4
3 4 2
1
2 1 5 6
3 1 3
1
*/

C++11(clang++ 3.9) 解法, 执行用时: 1091ms, 内存消耗: 59232K, 提交时间: 2018-11-16 21:14:20

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define mp make_pair
#define pb push_back
#define xx first
#define yy second
typedef long long ll;
typedef pair<int,int> pii;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=300010;
struct Segment {
	ll maxv[maxn<<2],sumv[maxn<<2],setv[maxn<<2];
	void update(int o,int l,int r,int ql,int qr,ll val) {
		if(ql<=l&&r<=qr) {setv[o]=maxv[o]=val;sumv[o]=val*(r-l+1);return;}
		int mid=l+r>>1,lc=o<<1,rc=lc|1;
		if(setv[o]>=0) {
			setv[lc]=setv[rc]=maxv[lc]=maxv[rc]=setv[o];
			sumv[lc]=setv[o]*(mid-l+1);sumv[rc]=setv[o]*(r-mid);
			setv[o]=-1;
		}
		if(ql<=mid) update(lc,l,mid,ql,qr,val);
		if(qr>mid) update(rc,mid+1,r,ql,qr,val);
		maxv[o]=max(maxv[lc],maxv[rc]);
		sumv[o]=sumv[lc]+sumv[rc];
	}
	ll getsum(int o,int l,int r,int ql,int qr) {
		if(!qr) return 0;
		if(ql<=l&&r<=qr) return sumv[o];
		if(setv[o]>=0) return setv[o]*(min(r,qr)-max(l,ql)+1);
		ll res=0;
		int mid=l+r>>1,lc=o<<1,rc=lc|1;
		if(ql<=mid) res+=getsum(lc,l,mid,ql,qr);
		if(qr>mid) res+=getsum(rc,mid+1,r,ql,qr);
		return res;
	}
	int find(int o,int l,int r,ll v) { //find the first position >=v
		if(maxv[o]<v) return -1;
		if(l==r) return l;
		int mid=l+r>>1,lc=o<<1,rc=lc|1;
		if(setv[o]>=0) {
			setv[lc]=setv[rc]=maxv[lc]=maxv[rc]=setv[o];
			sumv[lc]=setv[o]*(mid-l+1);sumv[rc]=setv[o]*(r-mid);
			setv[o]=-1;
		}
		if(maxv[lc]>=v) return find(lc,l,mid,v);
		return find(rc,mid+1,r,v);
	}
}T,Tr;
int n,m,gap;
ll A[maxn],pre[maxn],suf[maxn],ans;
void work() {
	rep(i,1,n) pre[i]=max(pre[i-1],A[i]);
	dwn(i,n,1) suf[i]=max(suf[i+1],A[i]);
	rep(i,1,n) if(pre[i-1]<suf[i+1]) gap=i;
	rep(i,1,n) T.update(1,1,n,i,i,pre[i]);
	dwn(i,n,1) Tr.update(1,1,n,n-i+1,n-i+1,suf[i]);
	ans=0;
	rep(i,1,gap) ans+=pre[i];
	rep(i,gap+1,n) ans+=suf[i];
}
int qleft(int l,int r,ll v) {
	if(l>r) return 0;
	int p=T.find(1,1,n,v);if(p<0) return 0;
	l=max(l,p);
	return l<=r?r-l+1:0;
}
int qright(int l,int r,ll v) {
	if(l>r) return 0;
	int p=n-Tr.find(1,1,n,v)+1;if(p==n+2) return 0;
	r=min(r,p);
	return l<=r?r-l+1:0;
}
int main() {
//	freopen("F.txt","r",stdin);
//	freopen("F.out","w",stdout);
	n=read();m=read();
	rep(i,1,n) A[i]=read();work();
	while(m--) {
		int t=read(),x,v;
		if(t==1) printf("%lld\n",ans);
		else if(t==2) {
			int l=read(),r=read(),v=read();
			printf("%d\n",qleft(l,min(gap,r),v)+qright(max(gap+1,l),r,v));
		}
		else {
			x=read(),v=read();A[x]+=v;
			int p;
			// premax
			p=T.find(1,1,n,A[x]);if(p<0) p=n+1;
			if(p>=x) T.update(1,1,n,x,p-1,A[x]);
			// premin
			p=n-Tr.find(1,1,n,A[x])+1;if(p==n+2) p=1;
			if(p<=x) Tr.update(1,1,n,n-x+1,n-p,A[x]);
			
		//	rep(i,1,n) printf("%lld%c",T.getsum(1,1,n,i,i),i==n?'\n':' ');
		//	rep(i,1,n) printf("%lld%c",Tr.getsum(1,1,n,n-i+1,n-i+1),i==n?'\n':' ');
			int l=1,r=n;
			while(l<r) {
				int mid=l+r>>1;
				if(T.getsum(1,1,n,mid-1,mid-1)>Tr.getsum(1,1,n,n-mid,n-mid)) r=mid;
				else l=mid+1;
			}
			gap=l-1;
		//	ans=0;
		//	rep(i,1,gap) ans+=T.getsum(1,1,n,i,i);
		//	rep(i,gap+1,n) ans+=Tr.getsum(1,1,n,n-i+1,n-i+1);
			
			ans=T.getsum(1,1,n,1,gap)+Tr.getsum(1,1,n,1,n-gap);
		//	rep(i,1,n) printf("%lld%c",T.getsum(1,1,n,i,i),i==n?'\n':' ');
		//	rep(i,1,n) printf("%lld%c",Tr.getsum(1,1,n,n-i+1,n-i+1),i==n?'\n':' ');
		//	printf("%d %lld\n",gap,ans);
		}
	}
	return 0;
}

上一题