Atcoder Beginner Contest 255 EX的无脑解法

前言

\(ABC\) 史上最简单 \(EX\) 题,考场因为 \(sb\) 了死卡 \(E\) ,错过了 \(F\)\(EX\) 这种无脑题。

难度

官方做法 \(2500\) ,本文做法 \(2000\)

算法标签

动态开点线段树。

题意简述

一个长为 \(n\) 的数列,初始全是 \(0\) ,每天第 \(i\) 个数会增加 \(i\) , \(Q\) 次询问,每次询问 \((l,r)\) 中数值之和,并把该区间清零。

\(n \le 10^{18},q \le 2e5\)

Solution

看完题,区间修改,区间查询,比较自然的想法是线段树吧。

先考虑询问,询问的时候,因为你每天的变化是有规律的,可以算出如果没有清零,当前区间的和,然后减去清零造成的影响,考虑这个影响,就是最后一次对这个区间操作的那一天之前的所有天数都白给。

所以每次对一个区间询问完和后,对这个询问区间用线段树赋值为当前天数,若之前不清零,能积累的值。

然后这个赋值的话,因为对于同一次区间修改,修改不同位置的数,要修改的值是不同的,看似不能简单的线段树赋值了,但是还是那句话,这个数列变化是极其有规律的,在给某个区间赋值一个和值的时候,可以用等差数列的性质 \(O(1)\) 算出和,对于子区间,性质是一致的。

这么做的话,复杂度是 \(O(Qlogn)\) ,空间复杂度是可怕的 \(O(4n)\) ,无了,考虑动态开点线段树,就是说每次需要一个树上的结点,我才会新建一个,在这类值域极大的问题当中,这样会节省不少空间。

那具体地,空间要开多大呢?注意到我们学习线段树的第一节课就分析过它的原理以及本质,是每次对于一个大区间都会拆成 \(O(logn)\) 个小区间合并计算,那么动态开点的话,每次询问最多增加 \(O(logn)\) 个点,那么空间复杂度最多 \(O(Qlogn)\) ,大约 \(2e7\) 吧。

这不就过了?

#include<cstdio>
#define N 10000005
#define p 998244353
#define inv 499122177
#define ll long long
using namespace std;
ll rt,D,L,R,n,q,cnt,tree[N<<2],lazy[N<<2],lson[N<<2],rson[N<<2];
ll val(ll l,ll r)
{
	return ((l+r)%p)*((r-l+1)%p)%p*inv%p;
}
void pushup(int node)
{
	tree[node]=(tree[lson[node]]+tree[rson[node]])%p;
}
void pushdown(ll l,ll r,ll node)
{
  	if(lazy[node])
	{
    	ll mid=(l+r)>>1;
    	if(!lson[node]) lson[node]=++cnt;
    	if(!rson[node]) rson[node]=++cnt;
    	tree[lson[node]]=val(l,mid)*(lazy[node]%p)%p;
    	tree[rson[node]]=val(mid+1,r)*(lazy[node]%p)%p;
    	lazy[lson[node]]=lazy[node];
    	lazy[rson[node]]=lazy[node];
    	lazy[node]=0;
  	}
}
 
void update(ll l,ll r,ll &node,ll x,ll y,ll v)
{
	if(r<x||l>y) return;
  	if(!node) node=++cnt;
  	if(x<=l&&r<=y)
	{
		tree[node]=val(l,r)*(v%p)%p;
        lazy[node]=v;
	  	return; 
	}
  	ll mid=(l+r)>>1;
  	pushdown(l,r,node);
  	update(l,mid,lson[node],x,y,v);
  	update(mid+1,r,rson[node],x,y,v);
  	pushup(node);
}
ll query(ll l,ll r,ll node,ll x,ll y)
{
  	if(r<x||l>y) return 0;
  	if(x<=l&&r<=y) return tree[node];
  	ll mid=(l+r)>>1;
  	pushdown(l,r,node);
  	return (query(l,mid,lson[node],x,y)+query(mid+1,r,rson[node],x,y))%p;
} 
int main()
{
  	scanf("%lld%lld",&n,&q);
  	while(q--)
	{
    	scanf("%lld%lld%lld",&D,&L,&R);
    	printf("%lld\n",(val(L,R)*(D%p)%p-query(1,n,rt,L,R)+p)%p);
    	update(1ll,n,rt,L,R,D);
  	}
}  ````
posted @ 2022-06-12 17:05  Constant1227  阅读(411)  评论(0)    收藏  举报