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);
}
} ````

浙公网安备 33010602011771号