[Ynoi2019] Happy Sugar Life 做题记录
省流:二维数点+分块
这里直接看的别人的题解,思路是来自于这篇题解。
这里给他进行一些补充:单块内只有\(O(B^2)\)个询问,但是处理答案的时候要离线求,不然空间复杂度是\(O(n\sqrt n)\)无法接受。对于二维前缀和的具体形式,我们设我们分块的是\(x\)轴,那么考虑\(y\)轴的变化,记录我们要求的\(y\)轴为\(l,r\),我们需要实现的是对于一个二位数点\([l,r-1],[r,n]\)增加,查询直接查询\(l,r\),注意此处要离散化,不然空间复杂度就会成为\(O(n^2)\),然后\(2,3\)块的处理相当于互换一下\(x,y\)轴,其余的应该比较好理解了,具体可以参考代码(个人认为可读性还是比较强的,有几个变量名有点抽象,但是根据我的写法也应该能猜出来对应的哪一个部分。)
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+10,B=500;
struct edge{
int x;
int y;
int xx;
int yy;
int gg;
int ll1;
int ll2;
long long ans;
}wen[maxn];
int n,m,p[maxn],val[maxn],C[maxn],mu,pre[maxn],zhui[B+10][B+10],lin[maxn];
int lst[maxn],nxt[maxn],cnt,li[maxn],last,tp;
vector<int>cao[maxn];
inline int lowbit(int q){
return q&(-q);
}
inline void add(int q,int w){
for(int i=q;i<=n;i+=lowbit(i)){
C[i]+=w;
}
return;
}
inline int query(int q){
int he=0;
for(int i=q;i;i-=lowbit(i)){
he+=C[i];
}
return he;
}
inline void solve(){
for(int i=1;i<=m;i++){
wen[i].gg=0;
}
for(int l=1,r;l<=n;l=r+1){
r=min(l+B-1,n);
for(int i=1;i<=n;i++){
pre[i]=0;
}
for(int i=l;i<=r;i++){
pre[p[i]]++;
}
for(int i=1;i<=n;i++){
pre[i]+=pre[i-1];
}
cnt=0;
for(int i=l;i<=r;i++){
li[++cnt]=p[i];
}
sort(li+1,li+1+cnt);
cnt=unique(li+1,li+1+cnt)-li-1;
tp=0;
last=0;
for(int i=1;i<=n;i++){
while(tp<cnt&&li[tp+1]<=i){
tp++;
last=tp;
}
lst[i]=last;
}
tp=cnt+1;
last=tp;
for(int i=n;i>=1;i--){
while(tp>0&&li[tp-1]==i){
tp--;
last=tp;
}
nxt[i]=last;
}
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++){
zhui[i][j]=0;
}
}
for(int i=l;i<=r;i++){
for(int j=i+1;j<=r;j++){
if(p[i]<p[j]){
zhui[nxt[p[i]]][nxt[p[j]]]++;
zhui[nxt[p[j]]][nxt[p[j]]]--;
}
}
}
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++){
zhui[i][j]+=zhui[i][j-1];
}
}
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++){
zhui[i][j]+=zhui[i-1][j];
}
}
for(int i=1;i<=m;i++){
if(wen[i].x<=l&&r<=wen[i].y){
wen[i].ans-=wen[i].gg*(pre[wen[i].yy]-pre[wen[i].xx-1]);
wen[i].ans-=zhui[lst[wen[i].xx-1]][lst[wen[i].yy]];
wen[i].gg+=pre[wen[i].xx-1];
}
else if(r>=wen[i].x&&l<=wen[i].y){
for(int j=max(l,wen[i].x);j<=min(r,wen[i].y);j++){
if(p[j]<wen[i].xx){
wen[i].gg++;
}
else if(p[j]<=wen[i].yy){
wen[i].ans-=wen[i].gg;
}
}
}
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>p[i];
}
for(int i=1;i<=m;i++){
cin>>wen[i].x>>wen[i].y>>wen[i].xx>>wen[i].yy;
cao[wen[i].x-1].push_back(i);
cao[wen[i].y].push_back(i);
}
for(int i=1;i<=n;i++){
val[i]=query(p[i]);
add(p[i],1);
for(int j=0;j<cao[i].size();j++){
mu=cao[i][j];
if(wen[mu].x-1==i){
wen[mu].ll1=query(wen[mu].xx-1);
wen[mu].ll2-=query(wen[mu].yy)-query(wen[mu].xx-1);
}
else{
wen[mu].ll2+=query(wen[mu].yy)-query(wen[mu].xx-1);
wen[mu].ans-=wen[mu].ll1*wen[mu].ll2;
}
}
}
for(int i=1;i<=n;i++){
C[i]=0;
}
for(int i=1;i<=n;i++){
add(p[i],val[i]);
for(int j=0;j<cao[i].size();j++){
mu=cao[i][j];
if(wen[mu].x-1==i){
wen[mu].ans-=query(wen[mu].yy)-query(wen[mu].xx-1);
}
else{
wen[mu].ans+=query(wen[mu].yy)-query(wen[mu].xx-1);
}
}
}
solve();
for(int i=1;i<=n;i++){
lin[p[i]]=i;
}
for(int i=1;i<=n;i++){
p[i]=lin[i];
}
for(int i=1;i<=m;i++){
swap(wen[i].x,wen[i].xx);
swap(wen[i].y,wen[i].yy);
}
solve();
for(int i=1;i<=m;i++){
cout<<wen[i].ans<<'\n';
}
return 0;
}
浙公网安备 33010602011771号