声明:本题解的做法非正解,使用这种思路可以通过本题的所有数据点,不保证没有 hack 数据可以卡掉我的思路 QAQ 。
前置芝士:珂朵莉树(ODT)
思路:
这里视 n , q n,q n,q 同阶。
首先,在随机数据的情况下,经过区间赋值的操作后,珂朵莉树的理论时间复杂度是 O ( n ) O(n) O(n) 的,普通地用 set 实现的珂朵莉树的时间复杂度是 O ( n log log n ) O(n\log\log n) O(nloglogn)。因此,在随机数据的情况下,可以使用珂朵莉树来达到维护操作的目的。
我们考虑,利用珂朵莉树维护每个区间的颜色,修改操作利用一个树状数组进行维护。遍历珂朵莉树上的每个区间,若当前区间颜色与修改区间相同,则在树状数组上进行区间修改操作,查询时,直接在树状数组上查询即可,时间复杂度为 O ( n log n log log n ) O(n\log n\log\log n) O(nlognloglogn) 。
在数据不随机的情况下,可能卡掉珂朵莉树的情况时,区间赋值的操作的区间长度总和一定是线性的,也就意味着,可将区间赋值的操作看为单点赋值。考虑每一种赋值操作都用一棵平衡树来维护,时间复杂度 O ( n log n ) O(n\log n) O(nlogn) 。考虑询问次数是线性的,在平衡树上的修改操作数就也是线性的,使用空间回收,空间复杂度为 O ( n ) O(n) O(n) 。
tips:
原则上来讲,以这种方式可以通过本题,但是由于空间限制得太为苛刻,不卡空间的话会 MLE (我空间没卡过去 QAQ)。其实由于本题的数据过水,通过测试可得,唯一卡珂朵莉树的点的区间赋值操作都是同一个值,(所以直接随便拿个线段树或者树状数组打暴力就能过了,我 AC 代码就这么写的)。
AC 代码
#include<iostream>
#include<cstdio>
#include<set>
#define int long long
#define MAXN 1000005
#define scit set <Chtholly> :: iterator
using namespace std;
int tmp[MAXN]={
},n,q;
struct query{
char op; signed t1,t2,t3;
}Q[MAXN]={
};
//-------------------------------暴力------------------------------------
struct seg{
signed l,r; int val,tag;
};
struct Segmenttree{
seg tree[MAXN<<2];
void pushup(int p){
tree[p].val=tree[p<<1].val+tree[p<<1|1].val;
}
void buildtree(int p,int l,int r){
tree[p].l=l; tree[p].r=r;
if(l==r) tree[p].val=0;
else{
int mid=l+r>>1;
buildtree(p<<1,l,mid);
buildtree(p<<1|1,mid+1,r);
pushup(p);