题解:P10540 [THUPC 2024 决赛] 古明地枣的袜子
本题解并非正解的分块+分治,学习正解请看其他题解。
双倍经验
P13827 P10540 题目一模一样,后者数据较水。
题意
给定
做法
很容易想到
原本还想尝试分块代替线段树,可以做到
分块 plus 就是可以做到
接下来看这道题,注意到前缀加只会改变
设小块块长为
但到这里交上去还是会WA,原因是在处理最后面的散块时会统计到
这样我们终于用暴力通过了这题,并且因为正解的超大常数,这种方法是优于大部分正解的。
代码
#include<bits/stdc++.h>
#define x first
#define y second
//不要乱开long long
#define ll long long
#define inf 1000000000000000000
#define max(A,B) (A)>(B) ? (A) : (B)
using namespace std;
const int N=5e5+10;
int n,m,pos[N],B=750;
ll w[N],tag1[(N>>3)+10],tag2[(N>>6)+10],mx1[(N>>3)+10],mx2[(N>>6)+10],ans[N],sum[N];
pair <int,int> a[N];
//莫队排序
struct node{
int l,r,id;
bool operator < (const node &t) const{
return pos[l]==pos[t.l] ? ((pos[l]&1) ? r<t.r : r>t.r) : pos[l]<pos[t.l];
}
}q[N];
//循环展开
#define c(p) tg+=w[p],mx=max(mx,tg)
#define cc(p) mx=max(mx,mx1[p]+tg),tg+=tag1[p]
#define ccc(p) mx=max(mx,mx2[p]+tg),tg+=tag2[p]
void update(int x,int y){
//下标从0开始,便于分块。
--x;
w[x]+=y;
tag1[x>>3]+=y;
tag2[x>>6]+=y;
ll tg=0,mx=-inf;
int i=(x>>3)<<3;
c(i+7),c(i+6),c(i+5),c(i+4),c(i+3),c(i+2),c(i+1),c(i);
mx1[x>>3]=mx;
tg=0,mx=-inf,i=(x>>6)<<3;
cc(i+7),cc(i+6),cc(i+5),cc(i+4),cc(i+3),cc(i+2),cc(i+1),cc(i);
mx2[x>>6]=mx;
}
ll query(){
ll mx=-inf,tg=0,i=(n-1)>>6;
for(;i>=7;i-=8) ccc(i),ccc(i-1),ccc(i-2),ccc(i-3),ccc(i-4),ccc(i-5),ccc(i-6),ccc(i-7);
for(;i>=0;--i) ccc(i);
return mx;
}
void add(int i){
update(a[i].x,a[i].y);
}
void del(int i){
update(a[i].x,-a[i].y);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y,pos[i]=(i-1)/B+1;
if(a[i].x==n) sum[i]+=a[i].y,a[i].y=0;
sum[i]+=sum[i-1];
}
for(int i=1;i<=m;i++) cin>>q[i].l>>q[i].r,q[i].id=i;
sort(q+1,q+m+1);
int L=1,R=0;
//莫队板子
for(int i=1;i<=m;i++){
while(R<q[i].r) add(++R);
while(L>q[i].l) add(--L);
while(R>q[i].r) del(R--);
while(L<q[i].l) del(L++);
ans[q[i].id]=max((ll)0,query())+sum[q[i].r]-sum[q[i].l-1];
}
for(int i=1;i<=m;i++) cout<<ans[i]<<"\n";
return 0;
}
P13827提交记录 P10540提交记录