题目背景
一般遇到一道恶心数据结构题时,我们会说它是良心蓝题,简称lxl题
题面
给定 n , m , A n,m,A n,m,A ,维护由序列构成的序列 a 1 , . . . , a n a_1,...,a_n a1,...,an ,初始 a i a_i ai 都包含一个元素 A + 1 A+1 A+1 ;
共 m m m 次操作,操作有两类:
-
修改操作:给定 l , r , x l,r,x l,r,x ,对 l ≤ i ≤ r l\leq i\leq r l≤i≤r ,在序列 a i a_i ai 开头插入元素 x x x ;
-
查询操作:给定 l , r l,r l,r ,查询 ∑ i = l r F ( a i , A ) \sum_{i=l}^{r} F(a_i,A) ∑i=lrF(ai,A) ;
其中 F ( a i , A ) F(a_i,A) F(ai,A) 等于 a i a_i ai 最短的前缀长度,满足该前缀所有元素的积大于 A A A 。
输入格式
第一行三个整数 n , m , A n,m,A n,m,A ;
接下来 m m m 行,每行 1 , l , r , x 1,l,r,x 1,l,r,x 表示一个修改操作, 2 , l , r 2,l,r 2,l,r 表示一个查询操作 。
输出格式
对于每个查询操作输出一行答案。
样例
5 20 10
1 4 4 166348285
2 2 5
2 1 5
1 1 2 10
1 4 4 3
1 4 5 6
2 5 5
1 5 5 1
1 2 3 1
2 5 5
2 5 5
2 3 4
2 3 3
2 4 5
2 4 4
1 2 5 5
1 5 5 9
1 1 4 5
2 5 5
2 1 4
4
5
2
3
3
4
2
5
2
2
8
数据范围
1 ≤ n , m ≤ 5 × 1 0 5 , 1 ≤ A , x ≤ 1 0 9 1\leq n,m\leq 5\times 10^5,1\leq A,x\leq 10^9 1≤n,m≤5×105,1≤A,x≤109 。
5 s , 512 m b \rm5s~,~512mb 5s , 512mb
题解
使用差分,可以将区间查询分为两次前缀查询,然后我们就可以在大序列上做扫描线。
把询问和修改都离线下来。我们维护当前位置的时间轴,一次修改拆成两次后缀修改。
用线段树维护每一时刻对应的答案,维护时间区间内的修改操作个数和 x x x 的积(方便线段树上二分求出单点答案)。再用set维护 x > 1 x>1 x>1 的操作位置。
每当我们加入或删除一个修改操作时,会对时间轴上后面 log A \log A logA 个 x > 1 x>1 x>1 的位置以及这些位置之间的时间产生影响。假设这些时间点分别是 t 1 , t 2 , . . . , t k t_1,t_2,...,t_k t1,t2,...,tk ,由于答案的性质, [ t 1 , t 2 ) , . . . [ t k , m ) [t_1,t_2),...[t_k,m) [t1,t2),...[tk,m) 这些区间内的答案变化量都是一致的,可以直接区间修改。
但是我们需要的是前缀所有位置的答案和,所以我们可以再差分一下。每当对一个区间答案增加 x x x 时,假设当前扫描到大序列 i i i 处,就直接区间增加 x × ( n − i + 1 ) x\times (n-i+1) x×(n−i+1) ,对后面的所有 a i a_i ai 都统计贡献。这样一来,满足我们扫到 i i i 时, a i , a i + 1 , . . . , a n a_i,a_{i+1},...,a_n ai,ai+1,...,an 各个时间点的答案都是一样的。我们只需要将该时间点的全局贡献减去 ( a i 在该时间点的贡献 ) × ( n − i ) (a_i 在该时间点的贡献)×(n-i) (ai在该时间点的贡献)×(n−i) ,就可以得到该前缀在某时间的贡献。
时间复杂度 O ( n log 2 n ) O(n\log^2n) O(nlog2n) ,需要精细卡常,智慧卡常,用高效的数据结构,比如zkw线段树。
CODE
#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#pragma GCC optimize(2)
using namespace std;
#define MAXN 500005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define PR pair<int,int>
#define UIN unsigned int
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
#define getchar() xchar()
inline LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
inline void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
inline void AIput(LL x,int c) {putnum(x);putchar(c);}
int n,m,s,o,k;
inline int mult(int a,int b) {LL x=a*1ll*b;return x>=0x3f3f3f3f ? 0x3f3f3f3f:x;}
int A,cnq,qx[MAXN];
LL as[MAXN];
vector<int> cg[MAXN];
vector<PR> bu[MAXN];
int sm[MAXN<<2],tre[MAXN<<2],M;
LL ksks[MAXN<<2];
void maketree(int n) {
M=1;while(M<n+2)M<<=1;
for(int i = (M<<1)-1;i > 0;i --) tre[i] = 1;
for(int i = M;i > 0;i >>= 1) tre[i] = A+1;
}
inline void addpo(int x,int y,int c) {
int s=M+x;tre[s]=y;sm[s]=c;s>>=1;
while(s)tre[s]=mult(tre[s<<1],tre[s<<1|1]),sm[s]=sm[s<<1]+sm[s<<1|1],s>>=1;
}
inline void addans(int l,int r,LL y) {
for(int s=M+l-1,t=M+r+1;(s>>1)^(t>>1);s>>=1,t>>=1) {
if(!(s&1)) ksks[s^1] += y;
if(t & 1) ksks[t^1] += y;
} return ;
}
inline LL findp(int x) {
int s=M+x;LL as=0;
while(s) as+=ksks[s],s>>=1;
return as;
}
inline int findlftas(int x) {
int mt = 1,ct = 0;
for(int t=M+x+1;t>0;t>>=1) {
if(t & 1) {
int nx = mult(mt,tre[t^1]);
if(nx <= A) mt = nx,ct += sm[t^1];
else {
int s = t^1;
while(s<M) {
nx = mult(mt,tre[s<<1|1]);
if(nx <= A) mt = nx,ct += sm[s<<1|1],s<<=1;
else s = s<<1|1;
}
break;
}
}
} return ct;
}
set<int> st;
int lp[MAXN],rp[MAXN],pre[MAXN];
void addq(int x,int op,int fr) {
static int ar[105],tp;
static int ps[105];
ar[tp = 1] = x;
int tl = *st.upper_bound(x),mt = 1;
while(tl <= m && mt <= A) ar[++ tp] = tl,mt = mult(mt,qx[tl]),tl = rp[tl];
for(int i = 1;i <= tp;i ++) {
ps[i] = (pre[ar[i]] == -1||i == 1 ? (pre[ar[i]] = findlftas(ar[i])):pre[ar[i]]);
} ar[tp + 1] = m+1;
if(op>0) {
if(qx[x] > 1) {
st.insert(x); auto tl = st.find(x),tr = tl;
tl --; lp[x] = *tl; rp[*tl] = x;
tr ++; lp[*tr] = x; rp[x] = *tr;
}
addpo(x,qx[x],1);
}
else {
if(qx[x] > 1) {
int s = lp[x],o = rp[x];
rp[s] = o; lp[o] = s; st.erase(x);
}
addpo(x,1,0);
}
for(int i = 1;i <= tp;i ++) {
int nw = findlftas(ar[i]);
addans(ar[i],ar[i+1]-1,(nw-ps[i])*1ll*fr);
pre[ar[i]] = nw;
} return ;
}
int main() {
n = read();m = read();A = read();
qx[0] = A+1; qx[m+1] = A+1;
st.insert(0); st.insert(m+1); rp[0] = m+1; lp[m+1] = 0;
maketree(m);
for(int i = 1;i <= m;i ++) {
pre[i] = -1;
k = read();
if(k == 1) {
s = read(); o = read(); qx[i] = read();
cg[s].push_back(i); cg[o+1].push_back(-i);
}
else {
s = read();o = read();
cnq ++;
bu[s-1].push_back({i,-cnq});
bu[o].push_back({i,cnq});
as[cnq] = o-s+1;
}
}
for(int i = 1;i <= n;i ++) {
for(int j:cg[i]) {
if(j>0) addq(j,1,n-i+1);
else addq(-j,-1,n-i+1);
}
for(auto &j:bu[i]) {
int x = j.FI;
LL nm = findp(x) - findlftas(x)*1ll*(n-i);
if(j.SE > 0) as[j.SE] += nm;
else as[-j.SE] -= nm;
}
}
for(int i = 1;i <= cnq;i ++) {
AIput(as[i],'\n');
}
return 0;
}