*题解:P3863 序列
解析
将序列视作一维,时间视作一维,那么查询和修改可以看作是在二维平面上的操作。具体地,如果令横轴为序列维,从左至右下标逐渐增加,纵轴为时间维,从下至上时刻逐渐变大。那么对于一次发生在第 \(i\) 秒的修改 \((l,r,x)\),其相当于对左上角为 \((l,q)\),右下角为 \((r,i)\) 的矩形区域加上 \(x\),\(q\) 为题目中的询问组数,也是最大时刻。对于一次发生在第 \(i\) 秒的查询 \((p,y)\),其相当于统计第 \((p,0)\) 至 \((p,i - 1)\) 中大于等于 \(y\) 的点的个数。
考虑扫描线,扫序列维,用数据结构维护时间维。对于修改,我们使用差分,将每个修改拆成在位置 \(l\) 加 \(x\) 和在位置 \(r + 1\) 减 \(x\);对于查询,要求大于等于 \(y\) 的点的个数,我们使用分块,每个块内维护原始序列和排序后序列,查询时对整块进行二分,散块暴力即可。
时间复杂度 \(O(nB\log B)\),\(B\) 为块长。
代码
#include <bits/stdc++.h>
#define ls(x) (((x) << 1))
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
const int N = 3e5 + 5,B = 300;
struct Q{
int op,t,p,x;
friend bool operator < (Q a,Q b){
return a.p != b.p ? a.p < b.p : a.op < b.op;
}
};
int a[N];
int n,q;
ll tag[N / B + 5],num[N],ori[N],srt[N],l[N / B + 5],r[N / B + 5];
void build(int n){
int cnt = 0;
for(int i=1;(i - 1) * B <= q;i++){
cnt++;
l[i] = (i - 1) * B;
r[i] = min(i * B - 1,q);
}
for(int i=1;i<=cnt;i++){
for(int j=l[i];j<=r[i];j++){
num[j] = i;
}
}
}
void add(int p,int x){
if(num[p] == num[q]){
for(int i=p;i<=q;i++){
ori[i] += x;
}
for(int i=l[num[p]];i<=r[num[p]];i++){
ori[i] += tag[num[p]];
srt[i] = ori[i];
}
tag[num[p]] = 0;
sort(srt + l[num[p]],srt + r[num[p]] + 1);
return;
}
for(int i=num[p] + 1;i<=num[q] - 1;i++){
tag[i] += x;
}
for(int i=l[num[p]];i<=r[num[p]];i++){
ori[i] += tag[num[p]];
if(i >= p) ori[i] += x;
srt[i] = ori[i];
}
sort(srt + l[num[p]],srt + r[num[p]] + 1);
tag[num[p]] = 0;
for(int i=l[num[q]];i<=r[num[q]];i++){
if(i >= p) ori[i] += x;
ori[i] += tag[num[q]];
srt[i] = ori[i];
}
sort(srt + l[num[q]],srt + r[num[q]] + 1);
tag[num[q]] = 0;
}
int ask(int p,int x){
int res = 0;
if(num[p] == num[0]){
for(int i=0;i<=p;i++){
res += (ori[i] + tag[num[p]]) >= x;
}
return res;
}
for(int i=num[0] + 1;i<=num[p] - 1;i++){
int t = lower_bound(srt + l[i],srt + r[i] + 1,x - tag[i]) - srt;
res += r[i] - t + 1;
}
for(int i=0;i<=r[num[0]];i++){
res += (ori[i] + tag[num[0]]) >= x;
}
for(int i=l[num[p]];i<=p;i++){
res += (ori[i] + tag[num[p]]) >= x;
}
return res;
}
vector<Q> qry;
int res[N];
int read(){
int a = 1,x = 0;
char ch = getchar();
while(ch > '9' || ch < '0'){
if(ch == '-') a = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return a * x;
}
signed main(){
// ios::sync_with_stdio(false);
// cin.tie(0),cout.tie(0);
n = read(),q = read();
build(q);
for(int i=1;i<=n;i++){
a[i] = read();
qry.push_back({1,0,i,a[i]});
qry.push_back({1,0,i + 1,-a[i]});
}
for(int i=1;i<=q;i++){
int op;
op = read();
if(op == 1){
int l,r,x;
l = read(),r = read(),x = read();
qry.push_back({1,i,l,x});
qry.push_back({1,i,r + 1,-x});
}else{
int p,y;
p = read();
y = read();
qry.push_back({2,i,p,y});
}
}
memset(res,-1,sizeof(res));
sort(qry.begin(),qry.end());
int now = 0;
for(int i=1;i<=n;i++){
while(now < qry.size() && qry[now].p == i){
if(qry[now].op == 1){
add(qry[now].t,qry[now].x);
}else{
res[qry[now].t] = ask(qry[now].t - 1,qry[now].x);
}
now++;
}
}
for(int i=1;i<=q;i++){
if(res[i] != -1){
cout<<res[i]<<'\n';
}
}
return 0;
}

浙公网安备 33010602011771号