ahhhh留下点会议行不行
分块
using namespace std;
#define int long long
const int N = 1e6+10;
int n, m, q;
int a[N], b[N];
int l[N], r[N];//存块的左右端点
int belong[N], add[N], sum[N];//belong表示属于哪个块
int B;
void update(int x, int y, int c) {
if(belong[x]==belong[y]) {//在同一块里暴力更新
for(int i=x; i<=y; i++) a[i]+=c;
sum[belong[x]]+=(y-x+1)*c;
return ;
}
for(int i=belong[x]+1; i<=belong[y]-1; i++) add[i]+=c;//好多块来个lazy标记
for(int i=x; i<=r[belong[x]]; i++) a[i]+=c;//在同一块里暴力更新
sum[belong[x]]+=(r[belong[x]]-x+1)*c;
for(int i=l[belong[y]]; i<=y; i++) a[i]+=c;//在同一块里暴力更新
sum[belong[y]]+=(y-l[belong[x]]+1)*c;
}
int ask(int x, int y) {
int ans=0;
if(belong[x]==belong[y]) {
for(int i=x; i<=y; i++) ans+=a[i]+add[belong[x]];
return ans;
}
for(int i=belong[x]+1; i<=belong[y]-1;i++) {
ans+=sum[i]+add[i]*B;
}
for(int i=x; i<=r[belong[x]]; i++) ans+=a[i]+add[belong[x]];
for(int i=l[belong[y]]; i<=y; i++) ans+=a[i]+add[belong[y]];
return ans;
}
signed main() {
cin>>n>>q;
for(int i=1; i<=n; i++) cin>>a[i];
B=sqrt(n);
int num=(n+B-1)/B;
for(int i=1; i<=n; i++) belong[i]=(i+B-1)/B, sum[belong[i]]+=a[i];
for(int i=1; i<=num; i++) l[i]=(i-1)*B+1, r[i]=i*B;
for(int i=1; i<=num; i++) sort(b+l[i], b+r[i]+1);
int c, x, y, w;
for(int i=1;i<=q;i++) {
cin>>c>>x>>y;
if(c==1) cin>>w, update(x, y, w);
else cout<<ask(x, y)<<endl;
}
return 0;
}
给出一个长为 的数列,以及 个操作,操作涉及区间加法,询问区间内小于某个值 的前驱(比其小的最大元素)。
问块里小于c的想到二分
对于零散块的更新也要这个零散块的整个块进行sort
复杂度
O
(
q
∗
s
q
r
t
(
N
)
l
o
g
(
s
q
r
t
(
N
)
)
)
O(q*sqrt(N)log(sqrt(N)))
O(q∗sqrt(N)log(sqrt(N)))
using namespace std;
#define int long long
const int N = 1e6+10;
int n, q, a[N], b[N], l[N], r[N], belong[N], add[N], B;
void reset(int x) {
for(int i=l[belong[x]]; i<=r[belong[x]]; i++) b[i]=a[i];
sort(b+l[belong[x]], b+r[belong[x]]+1);
}
void update(int x, int y, int c) {
if(belong[x]==belong[y]) {
for(int i=x; i<=y; i++) a[i]+=c;
reset(x);
return ;
}
for(int i=x; i<=r[belong[x]]; i++) a[i]+=c;
for(int i=l[belong[y]]; i<=y; i++) a[i]+=c;
reset(x);
reset(y);
for(int i=belong[x]+1; i<=belong[y]-1; i++) add[i]+=c;
}
int ask(int x, int y, int c) {
int ans=-2e18;
if(belong[x]==belong[y]) {
for(int i=x; i<=y; i++) {
if(a[i]+add[belong[x]]<c) ans=max(ans, a[i]+add[belong[x]]);
}
if(ans==-2e18) ans=-1;
return ans;
}
for(int i=x; i<=r[belong[x]]; i++) if(a[i]+add[belong[x]]<c) ans=max(ans, a[i]+add[belong[x]]);
for(int i=l[belong[y]]; i<=y; i++) if(a[i]+add[belong[y]]<c) ans=max(ans, a[i]+add[belong[y]]);
for(int i=belong[x]+1; i<=belong[y]-1;i++) {
int qq=lower_bound(b+l[i], b+r[i]+1, c-add[i])-b-1;//二分查找的是c-add[i]
if(b[qq]<c-add[i]) ans=max(ans, b[qq]+add[i]);//这里调了好久 最后的ans要和b[qq]+add[i]比较不是b[i]//有可能是找不到就返回首位置就要if判断一下
}
if(ans==-2e18) ans=-1;
return ans;
}
莫队
P4137 Rmq Problem / mex莫队+分块
求区间mex直接分块
询问通过分块sort一下然后莫队跑
using namespace std;
const int N = 2e5 + 5;
const int B = sqrt(N);
int a[N], cnt[N], n, m, tans, ans[N], zhengge[N];//记整个块内有的数的数量
int l=1, r=0;//一直t一个点把l=1,r=0;从主函数搬到外面就不t了。。。。快了0.03s
struct Q {
int l, r, id;
bool operator<(const Q &t) const {
return l/B==t.l/B ? r<t.r: l/B<t.l/B;
}
}q[N];
int get(int x) {return x/B;}
void update(int x, int f) {
cnt[x]+=f;
if(cnt[x]==0&&f==-1) zhengge[get(x)]+=f;
else if(cnt[x]==1&&f==1) zhengge[get(x)]+=f;
}
int main() {
n=read(); m=read();
for(int i=1; i<=n; i++) a[i]=read();
for(int i=1; i<=m; i++) {
q[i].l=read();q[i].r=read();
q[i].id=i;
}
sort(q+1, q+m+1);
for(int i=1; i<=m; i++) {
while(l<q[i].l) update(a[l++], -1);
while(l>q[i].l) update(a[--l], 1);
while(r<q[i].r) update(a[++r], 1);
while(r>q[i].r) update(a[r--], -1);
int qq=0;
for(int k=0; k<=B; k++) {
if(zhengge[k]<B) {
for(int j=k*B; j<=k*B+B-1; j++) {
if(cnt[j]==0) {
ans[q[i].id]=j;
qq=1;
break;
}
}
}
if(qq) break;
}
}
for(int i=1; i<=m; i++) {
cout<<ans[i]<<"\n";
}
return 0;
}
XOR and Favorite Numbercf2200
求区间段异或所以想到存区间前缀和
假设现在位置为
R
R
R,异或前缀和为
x
x
x,我们需要多少个左区间满足
x
x
x^
p
r
e
[
L
−
1
]
=
=
k
pre[L-1]==k
pre[L−1]==k 等价于有多少个
p
r
e
[
L
−
1
]
=
=
x
pre[L-1]==x
pre[L−1]==x ^
k
k
k,用一个桶去装
但是由于区间
[
L
,
R
]
[L, R]
[L,R]的异或值为
p
r
e
[
R
]
pre[R]
pre[R] ^
p
r
e
[
L
−
1
]
pre[L-1]
pre[L−1]所以需要把左端点移动一下
#define int long long//tans和ans[]都会爆int 找学长找了bug
using namespace std;
const int N = 2e6 + 5;
int a[N], cnt[N], n, m, k, tans, ans[N], B;
struct Q {
int l, r, id;
bool operator<(const Q &t) const {
return l/B==t.l/B ? r<t.r: l/B<t.l/B;
}
}q[N];
void update(int x, int f) {
if(f==1) tans+=cnt[x^k], cnt[x]++;
else cnt[x]--, tans-=cnt[x^k];
}
signed main() {
n=read();m=read();k=read();
B=sqrt(1.0*n);
for(int i=1; i<=n; i++) a[i]=read(), a[i]=a[i-1]^a[i];//前缀异或值
for(int i=1; i<=m; i++) {
q[i].l=read();q[i].r=read();
q[i].l--;//主要因为是pre[L-1]//不这样写的话要cnt[0]并且下面的第一个update的a[l++]变为a[l-1]再l++第二个要变为
q[i].id=i;
}
sort(q+1, q+m+1);
int l=1, r=0;
for(int i=1; i<=m; i++) {
while(l<q[i].l) update(a[l++], -1);
while(l>q[i].l) update(a[--l], 1);
while(r<q[i].r) update(a[++r], 1);
while(r>q[i].r) update(a[r--], -1);
ans[q[i].id]=tans;
}
for(int i=1; i<=m; i++) {
cout<<ans[i]<<"\n";
}
return 0;
}
D. Cut and Stickcf2000(没补
P7416 [USACO21FEB] No Time to Dry P个人赛5(没补
Frequent values 可能莫队(
带修改的莫队
给一个长为n的序列m个操作
1
l
r
1 l r
1lr问
[
l
,
r
]
[l, r]
[l,r]内不相同的个数
2
p
x
2 p x
2px将
a
[
p
]
a[p]
a[p]修改为
x
x
x
using namespace std;
const int N = 10000 + 5;
const int B = pow(N, 2.0/3);
struct Q {
int l, r, t, id;
bool operator < (const Q &b) const {
if(l/B==b.l/B) {
if(r/B==b.r/B) return t<b.t;
else return r/B<b.r/B;
}else return l/B<b.l/B;
}
}q[N];
struct M {
int p, x, y;
} md[N];//保存修改序列
int a[N], n, m, k, tim, tans, ans[N], cnt[N], b[N];//a原序列,b辅助数组
int l=1, r=0, t=0;
void update(int x, int f) {
cnt[x]+=f;
if(cnt[x]==0&&f==-1) tans--;
if(cnt[x]==1&&f==1) tans++;
}
void updateTime(int t, int f) {
if(f==1) {
if(l<=md[t].p&&md[t].p<=r) update(md[t].x, -1), update(md[t].y, 1);
a[md[t].p]=md[t].y;
}else {
if(l<=md[t].p&&md[t].p<=r) update(md[t].y, -1), update(md[t].x, 1);
a[md[t].p]=md[t].x;
}
}
int main() {
cin>>n>>m;
for (int i=1; i<=n; i++) {
cin>>a[i];
b[i]=a[i];
}
for (int i=1; i<=m; i++) {
int op, l, r;
cin>>op>>l>>r;
if (op==1) q[++k]={l, r, tim, k};
else {
md[++tim]={l, b[l], r};
b[l]=r;
}
}
sort(q+1, q+k+1);
for (int i=1; i<=k; i++) {
while(t<q[i].t) updateTime(++t, 1);
while(t>q[i].t) updateTime(t--, -1);
while(l<q[i].l) update(a[l++], -1);
while(l>q[i].l) update(a[--l], 1);
while(r<q[i].r) update(a[++r], 1);
while(r>q[i].r) update(a[r--], -1);
ans[q[i].id] = tans;
}
for (int i=1; i<=k; i++) printf("%d\n", ans[i]);
return 0;
}
笛卡尔树
886
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容