cdq分治
分析
-
将询问和查询拆开,有的时候有奇效(即使是只有查询的题目)
-
可以存在撤销操作,删除时需要考虑后面删掉了前面的情况
-
如果删除很简单,则没啥关系
-
如果删除很难,则可以采用时间回溯,先把所有删除操作做完,从后往前做,变成插入,时间复杂度一个\(lg\),如果插入和询问还需要分开时,时间复杂度再加一个\(lg\) ,但我感觉这个真和线段树分治没啥区别,也就是没啥用?
例题1
Luogu P6406 [COCI2014-2015#2] Norma
数据范围卡掉了万能的分块,考虑分治
只需要考虑跨过中线的答案
对于每个左边的点,右边可以分成3部分(如图分别表示max和min的位置)
显然,随着枚举的左边界向左移动,左边的max只会变大,min只会减小,而右边的两条分割线也会随之右移
对于每个左边界,计算它到r之间全部的答案
- 对于第一块左左,左边的max\(\times\)左边的min\(\times\)区间大小和
- 第二块左右,设max在左边,左边的max\(\times\)(右边的min\(\times\)区间大小和)=左边max\(\times\)(位于右边的块内的min和+左边块的大小\(\times\)右边的min和)
- 第三块右右,右边的max\(\times\)右边的min\(\times\)区间大小和=左边块的大小\(\times\)右边的maxmin和+右边块内的maxmin和
需要预处理右边mx的前缀和,右边mx的块的前缀和,右边mn的前缀和,右边mn的块的前缀和,右边mxmn的前缀和,右边mxmn的块的前缀和
\(O(nlgn)\)
WA了一次:没思考清楚左左时的区间大小和
#include<bits/stdc++.h>
#define ll long long
const int p=1e9;
using namespace std;
const int N=5e5+5;
int n,a[N],mx[N],mn[N],s0[N],s1[N],s2[N],t0[N],t1[N],t2[N];
int ans;
inline int mo(int x) {
return x>=p?x-p:x;
}
void work(int l,int r) {
if(l==r) {
ans=((ll)a[l]*a[l]+ans)%p;
return;
}
int mid=l+r>>1;
work(l,mid),work(mid+1,r);
int top=1;
mx[top]=mn[top]=s0[top]=t0[top]=s1[top]=t1[top]=a[mid+1];
t2[top]=s2[top]=(ll)a[mid+1]*a[mid+1]%p;
for(int i=mid+2;i<=r;i++) {
top++;
mx[top]=max(mx[top-1],a[i]);
mn[top]=min(mn[top-1],a[i]);
t0[top]=mo(t0[top-1]+mx[top]);
s0[top]=((ll)s0[top-1]+(ll)mx[top]*(i-mid))%p;
t1[top]=mo(t1[top-1]+mn[top]);
s1[top]=((ll)s1[top-1]+(ll)mn[top]*(i-mid))%p;
t2[top]=((ll)t2[top-1]+(ll)mn[top]*mx[top])%p;
s2[top]=((ll)s2[top-1]+(ll)mn[top]*mx[top]%p*(i-mid))%p;
}
int zd=0,zx=p,num1=0,num2=1;
for(int i=mid;i>=l;i--) {
zd=max(zd,a[i]),zx=min(zx,a[i]);
while(num1<top&&zd>=mx[num1+1]&&zx<=mn[num1+1]) num1++;
while(num2<=top&&!(zd<mx[num2]&&zx>mn[num2])) num2++;
if(num1) ans=((ll)ans+(ll)zd*zx%p*(((ll)(num1+mid-i+mid-i+3)*num1/2)%p))%p;
if(num1<num2-1) {
if(mx[num2-1]>zd) {
ans=((ll)ans+(ll)zx*((ll)(t0[num2-1]-t0[num1]+p)*(mid-i+1)%p+s0[num2-1]-s0[num1]+p))%p;
} else {
ans=((ll)ans+(ll)zd*((ll)(t1[num2-1]-t1[num1]+p)*(mid-i+1)%p+s1[num2-1]-s1[num1]+p))%p;
}
}
if(num2<=top) ans=((ll)ans+(ll)(t2[top]-t2[num2-1]+p)*(mid-i+1)+s2[top]-s2[num2-1]+p)%p;
}
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
work(1,n);
printf("%d\n",ans);
return 0;
}
模板
四维偏序
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5,M=4e5+5;
int n,m,q,ans[N];
struct A{int fl,x,y,z,id; }h[M],b[M],a[M],t[M];
void work3(int l,int r) {
if(l==r) return;
int mid=l+r>>1;
work3(l,mid),work3(mid+1,r);
int i=l,j=mid+1,k=l,num=0;
for(;i<=mid&&j<=r;k++) {
if(h[i].z<=h[j].z) {
b[k]=h[i];
if(h[i].fl==0) num++;
i++;
} else {
b[k]=h[j];
if(h[j].fl) ans[h[j].id]+=h[j].fl==1?num:-num;
j++;
}
}
for(;i<=mid;k++,i++) {
b[k]=h[i];
}
for(;j<=r;k++,j++) {
b[k]=h[j];
if(h[j].fl) ans[h[j].id]+=h[j].fl==1?num:-num;
}
for(int i=l;i<=r;i++) h[i]=b[i];
}
void work2(int l,int r) {
if(l==r) return;
int mid=l+r>>1;
work2(l,mid),work2(mid+1,r);
int i=l,j=mid+1,k=l,top=0;
for(;i<=mid&&j<=r;k++) {
if(t[i].y<=t[j].y) {
b[k]=t[i];
if(t[i].fl==0) {
h[++top]=t[i];
}
i++;
} else {
b[k]=t[j];
if(t[j].fl) {
h[++top]=t[j];
}
j++;
}
}
for(;i<=mid;k++,i++) {
b[k]=t[i];
}
for(;j<=r;k++,j++) {
b[k]=t[j];
if(t[j].fl) h[++top]=t[j];
}
for(int i=l;i<=r;i++) t[i]=b[i];
if(top) work3(1,top);
}
void work1(int l,int r) {
if(l==r) return;
int mid=l+r>>1;
work1(l,mid),work1(mid+1,r);
int i=l,j=mid+1,k=l,top=0;
for(;i<=mid&&j<=r;k++) {
if(a[i].x<=a[j].x) {
b[k]=a[i];
if(a[i].fl==0) {
t[++top]=a[i];
}
i++;
} else {
b[k]=a[j];
if(a[j].fl) {
t[++top]=a[j];
}
j++;
}
}
for(;i<=mid;k++,i++) {
b[k]=a[i];
}
for(;j<=r;k++,j++) {
b[k]=a[j];
if(a[j].fl) {
t[++top]=a[j];
}
}
for(int i=l;i<=r;i++) a[i]=b[i];
if(top) work2(1,top);
}
int main() {
int T; scanf("%d",&T);
while(T--) {
scanf("%d",&n); m=0,q=0;
for(int i=1;i<=n;i++) {
int op; scanf("%d",&op);
if(op==1) {
int x,y,z; scanf("%d%d%d",&x,&y,&z);
a[++m]=(A){0,x,y,z,0};
} else {
int x1,y1,z1,x2,y2,z2; scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
q++;
a[++m]=(A){1,x2,y2,z2,q};
if(x1>1) a[++m]=(A){-1,x1-1,y2,z2,q};
if(y1>1) a[++m]=(A){-1,x2,y1-1,z2,q};
if(z1>1) a[++m]=(A){-1,x2,y2,z1-1,q};
if(x1>1&&y1>1) a[++m]=(A){1,x1-1,y1-1,z2,q};
if(x1>1&&z1>1) a[++m]=(A){1,x1-1,y2,z1-1,q};
if(y1>1&&z1>1) a[++m]=(A){1,x2,y1-1,z1-1,q};
if(x1>1&&y1>1&&z1>1) a[++m]=(A){-1,x1-1,y1-1,z1-1,q};
}
}
work1(1,m);
for(int i=1;i<=q;i++) {
printf("%d\n",ans[i]);
}
memset(ans,0,sizeof(ans));
}
return 0;
}