题目链接
题意:维护一个序列。
有两种操作,一种叫做把[l,r]的大于x的数减掉x,
一种是查询[l,r]里面x的出现次数。
真红世界第一可爱(大声
简单粗暴的opt题目
好像整个序列里面的数再怎么变最小也就是0,而且变成0就不会动了
感觉可以分析一波复杂度不过还没有思路好像太早了点
在开始找思路之前先定义一个
U
=
1
0
5
U=10^5
U=105(本题数据上界)
查询怎么做?
主席树懒修改的话查询又一定要推到底,那可能要用某种奇怪的姿势搞分块暴力
一个块里面相同的那些数可以做成一个集合,修改其实就是把集合
i
i
i转移进
i
−
x
i-x
i−x。
(当然不能只转一个
c
n
t
cnt
cnt,不然待会暴力重构边缘块的时候就凉凉了)
这样暴力的,复杂度好像有点高吧?
那怎么做马?作为一个合格的能过这道题的分块至少也要
Θ
(
U
U
)
\Theta(U\sqrt{U})
Θ(UU)
这个复杂度真吗?
第一个操作是什么?把
[
l
,
r
]
[l,r]
[l,r]里面大于
x
x
x的减掉
x
x
x,
这两个
x
x
x有没有很玄,想想是不是能够摊还
M
x
[
i
]
Mx[i]
Mx[i]代表块
i
i
i的最大值,块的初势就是
M
x
[
i
]
≤
U
Mx[i]\le U
Mx[i]≤U
有
N
\sqrt{N}
N个块, 想想能不能做到
U
N
U\sqrt{N}
UN——也就是付出一点的代价至少让
M
x
Mx
Mx减少一点
修改的时候吧,对于
[
l
,
r
]
[l,r]
[l,r]里面的块,
如果
M
x
[
i
]
≤
x
Mx[i]\le x
Mx[i]≤x就跳过。
M
x
[
i
]
>
x
Mx[i]> x
Mx[i]>x,可以消耗
M
x
[
i
]
−
x
Mx[i]-x
Mx[i]−x次的费用使
M
x
[
i
]
Mx[i]
Mx[i]至少减少
m
i
n
(
x
,
M
x
[
i
]
−
x
)
min(x,Mx[i]-x)
min(x,Mx[i]−x)。
这个在
M
x
[
i
]
≤
2
x
Mx[i]\le 2x
Mx[i]≤2x的情况下代价等于势能减少量,很阔以
可是
2
x
<
M
x
[
i
]
2x < Mx[i]
2x<Mx[i]的情况下代价大于势能减少量,这就很不阔以了。
既然
M
x
Mx
Mx减少的量在这种情况下固定为
x
x
x了,那代价怎么说也得
≤
x
\le x
≤x吧?
实际上把
>
x
> x
>x的下移相当于把
≤
x
\le x
≤x的上移
x
x
x然后整体
−
x
-x
−x
于是修改的时候把
≤
x
\le x
≤x的拿来加
x
x
x,给块加一个整体
−
x
-x
−x的标记。
总的复杂度 Θ ( ( U + M ) N ) \Theta((U+M)\sqrt{N}) Θ((U+M)N)
ps.洛谷上面Input写错了,第二个操作应该是2 l r x,x写成了p(
真实的卡常数大赛
数据范围弱化
听说空间可以压下40M
不过我就不专门开个数据类型了(
Accepted 128076kb
4822B 15396ms
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#define reg register int
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
using namespace std;
char frBB[1<<12],*frS=frBB,*frT=frBB;
inline int read()
{
int x=0;char ch=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=x*10+ch-48,ch=getchar();
return x;
}
template<typename T>
inline void write(T x)
{
if(x>9)write(x/10);
putchar(x%10+48);
}
int N,M,siz,cnt,t;
int Ai[100005]={};
int lb[320]={},rb[320]={};
short belong[100005]={};
int root[320][100005]={};
int sub[320]={};
int mx[320]={};
int fa[100005]={};
int roottype[100005]={};
int rootcnt[100005]={};
inline int find(const int&x){return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
inline void merge(const int&id,const int&a,const int&b)
{
if(!root[id][b])
{
root[id][b]=root[id][a];
roottype[root[id][a]]=b;
}
else
{
fa[root[id][a]]=root[id][b];
rootcnt[root[id][b]]+=rootcnt[root[id][a]];
}
root[id][a]=0;
}
inline void preload(const reg&id)
{
mx[id]=0;
for(reg i=lb[id];i<=rb[id];++i)
{
mx[id]=max(mx[id],Ai[i]);
rootcnt[i]=1;
if(!root[id][Ai[i]])
{
root[id][Ai[i]]=i;
fa[i]=i;
roottype[i]=Ai[i];
}
else
{
fa[i]=root[id][Ai[i]];
rootcnt[fa[i]]+=rootcnt[i];
}
}
}
inline void _clear(const reg&id)
{
for(reg i=lb[id];i<=rb[id];++i)
{
Ai[i]=roottype[find(i)];
root[id][Ai[i]]=0;
Ai[i]-=sub[id];
}
for(reg i=lb[id];i<=rb[id];++i)fa[i]=0;
sub[id]=0;
}
inline void work(const reg&id,const reg&x)
{
if(mx[id]-sub[id]<=x)return;
if(mx[id]-sub[id]<2*x)
{
for(reg i=sub[id]+x+1;i<=mx[id];++i)if(root[id][i])merge(id,i,i-x);
mx[id]=min(mx[id],x+sub[id]);
}
else
{
for(reg i=sub[id]+1;i<=sub[id]+x;++i)if(root[id][i])merge(id,i,i+x);
sub[id]+=x;
}
}
inline void modify(const reg&l,const reg&r,const reg&x)
{
reg lblock=belong[l],rblock=belong[r];
if(lblock==rblock)
{
_clear(lblock);
for(reg i=l;i<=r;++i)if(Ai[i]>x)Ai[i]-=x;
preload(lblock);
}
else
{
_clear(lblock); _clear(rblock);
for(reg i=l;i<=rb[lblock];++i)if(Ai[i]>x)Ai[i]-=x;
for(reg i=lblock+1;i<rblock;++i)work(i,x);
for(reg i=lb[rblock];i<=r;++i)if(Ai[i]>x)Ai[i]-=x;
preload(lblock); preload(rblock);
}
}
inline int query(const reg&l,const reg&r,const reg&x)
{
reg lblock=belong[l],rblock=belong[r],ret=0;
if(lblock!=rblock)
{
t=x+sub[lblock];
for(reg i=l;i<=rb[lblock];++i)if(roottype[find(i)]==t)++ret;
t=x+sub[rblock];
for(reg i=lb[rblock];i<=r;++i)if(roottype[find(i)]==t)++ret;
for(reg i=lblock+1;i<rblock;++i)if(x<=mx[i]-sub[i])ret+=rootcnt[root[i][x+sub[i]]];
}
else
{
for(reg i=l;i<=r;++i)
{
if(roottype[find(i)]==x+sub[lblock])++ret;
}
}
return ret;
}
#define read() read()
#define write(x) write(x)
#define find(x) find(x)
#define merge(id,a,b) merge(id,a,b)
#define preload(id) preload(id)
#define _clear(id) _clear(id)
#define work(id,x) work(id,x)
#define modify(l,r,x) modify(l,r,x)
int main()
{
N=read(); M=read(); siz=sqrt(N); cnt=(N-1)/siz+1;
for(reg i=1;i<=N;++i)Ai[i]=read();
for(reg i=1;i<=cnt;++i)
{
lb[i]=(i-1)*siz+1;
rb[i]=i*siz;
if(i==cnt)rb[i]=N;
for(reg j=lb[i];j<=rb[i];++j)
{
rootcnt[j]=1;
belong[j]=i;;
mx[i]=max(mx[i],Ai[j]);
if(!root[i][Ai[j]])
{
fa[j]=j;
root[i][Ai[j]]=j;
roottype[j]=Ai[j];
}
else
{
fa[j]=root[i][Ai[j]];
rootcnt[fa[j]]+=rootcnt[j];
}
}
}
reg opt,l,r,x;
while(M--)
{
opt=read(); l=read(); r=read(); x=read();
if(opt==1)modify(l,r,x);
if(opt==2)write(query(l,r,x)),putchar('\n');
}
return 0;
}
F社咕咕咕
等两个月不知道能不能看见新作