CDQ分治
Mokia
如果单纯考虑一个点对一个块产生的贡献,是个五维偏序
把一个块分成4部分再合并,就变成了3维偏序
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+11;
const int ed=2e6;
struct qry_{
int xp,yp,xd,yd;
int ans;
}qry[N];
struct cz_{
int ty;
int x,y;
int w;
int t;
int fa,xs;
}opt[N];
int s,w,m;
int num;
int tre[ed+11];
inline int read()
{
int s=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9')
{
s=(s<<1)+(s<<3)+(ch^48);
ch=getchar();
}
return s;
}
int lowbit(int x){return x&-x;};
void insert(int x,int val)
{
while(x<=w)
{
tre[x]+=val;
x+=lowbit(x);
}
return;
}
int query(int x)
{
int sum=0;
while(x)
{
sum+=tre[x];
x-=lowbit(x);
}
return sum;
}
void add(int x,int y,int f,int xs)
{
++num;
opt[num]=(cz_){2,x,y,0,num,f,xs};
return;
}
bool cmp_by_x(cz_ a,cz_ b){return a.x!=b.x?a.x<b.x:a.y<b.y;}
bool cmp_by_t(cz_ a,cz_ b){return a.t<b.t;}
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid);
sort(opt+l,opt+mid+1,cmp_by_x);
sort(opt+mid+1,opt+r+1,cmp_by_x);
int p1=l,p2=mid+1;
while(p2<=r)
{
while(p1<=mid&&opt[p1].x<=opt[p2].x)
{
if(opt[p1].ty==1) insert(opt[p1].y,opt[p1].w);
++p1;
}
if(opt[p2].ty==2) opt[p2].w+=query(opt[p2].y);
++p2;
}
for(int j=l;j<p1;j++)
if(opt[j].ty==1)
insert(opt[j].y,-opt[j].w);
sort(opt+l,opt+r+1,cmp_by_t);
cdq(mid+1,r);
return;
}
signed main()
{
s=read();
w=read();
int ty,val;
while((ty=read())!=3)
{
if(ty==1) ++num,opt[num]=(cz_){1,read(),read(),read(),num};
else
{
qry[++m]=(qry_){read(),read(),read(),read()};
if(qry[m].xp-1>0&&qry[m].yp-1>0)
{
add(qry[m].xp-1,qry[m].yp-1,m,1);
add(qry[m].xp-1,qry[m].yd,m,-1);
add(qry[m].xd,qry[m].yp-1,m,-1);
add(qry[m].xd,qry[m].yd,m,1);
}
else if(qry[m].xp-1>0)
{
add(qry[m].xp-1,qry[m].yd,m,-1);
add(qry[m].xd,qry[m].yd,m,1);
}
else if(qry[m].yp-1>0)
{
add(qry[m].xd,qry[m].yp-1,m,-1);
add(qry[m].xd,qry[m].yd,m,1);
}
else add(qry[m].xd,qry[m].yd,m,1);
}
}
cdq(1,num);
// for(int i=1;i<=num;i++)if(opt[i].ty==2)cout<<opt[i].ty<<" "<<opt[i].x<<" "<<opt[i].y<<" "<<opt[i].w<<endl;
for(int i=1;i<=num;i++)
if(opt[i].ty==2)
qry[opt[i].fa].ans+=opt[i].w*opt[i].xs;
for(int i=1;i<=m;i++) printf("%lld\n",qry[i].ans);
return 0;
}
天使玩偶
把绝对值拆开,然后大力分类讨论
设当前(x1,y1)
左上的(x2,y2),x2-x1+y1-y2,维护\(min(x-y)\)
右上的,x2-x1+y2-y1,维护\(min(x+y)\)
其余两个同理
由于需要维护前缀最小值和后缀最小值,处理后缀最小值时,将query(x)改为query(inf-x)
这样在洛谷会T,把inf卡紧了,cdq时每次把y离散化,inf设为去重后的个数+1,然后就行了
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+11;
const int ed=1e6;
const int inf=2e6;
struct opt_{
int ty;
int t;
int x,y;
int ans;
}opt[N];
int n,m;
int num;
int tre1[ed+11],tre2[ed+11];
inline int read()
{
int s=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9')
{
s=(s<<1)+(s<<3)+(ch^48);
ch=getchar();
}
return s;
}
int max_(int a,int b){return a>b?a:b;}
int min_(int a,int b){return a>b?b:a;}
int lowbit(int x){return x&-x;}
bool cmp_x(opt_ a,opt_ b){return a.x!=b.x?a.x<b.x:a.y<b.y;}
bool cmp_t(opt_ a,opt_ b){return a.t!=b.t?a.t<b.t:cmp_x(a,b);}
void insert1(int x,int y)
{
while(x<=ed)
{
tre1[x]=min_(tre1[x],y);
x+=lowbit(x);
}
return;
}
void insert2(int x,int y)
{
while(x<=ed)
{
tre2[x]=min_(tre2[x],y);
x+=lowbit(x);
}
return;
}
void clear(int x)
{
int y=ed-x;
while(x<=ed)
tre1[x]=inf,x+=lowbit(x);
while(y<=ed)
tre2[y]=inf,y+=lowbit(y);
return;
}
int query1(int x)
{
int ans=inf;
while(x)
{
ans=min_(tre1[x],ans);
x-=lowbit(x);
}
return ans;
}
int query2(int x)
{
int ans=inf;
while(x)
{
ans=min_(tre2[x],ans);
x-=lowbit(x);
}
return ans;
}
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid);
sort(opt+l,opt+mid+1,cmp_x);
sort(opt+mid+1,opt+r+1,cmp_x);
int p1=l,p2=mid+1;
while(p2<=r)
{
while(p1<=mid&&opt[p1].x<=opt[p2].x)
{
if(opt[p1].ty==2){++p1;continue;};
insert1(opt[p1].y,-opt[p1].x-opt[p1].y);
insert2(ed-opt[p1].y,-opt[p1].x+opt[p1].y);
++p1;
}
if(opt[p2].ty==1) {++p2;continue;}
opt[p2].ans=min_(opt[p2].ans,min_(opt[p2].x+opt[p2].y+query1(opt[p2].y),opt[p2].x-opt[p2].y+query2(ed-opt[p2].y)));
++p2;
}
for(int i=l;i<p1;i++) if(opt[i].ty==1) clear(opt[i].y);
p1=mid,p2=r;
while(p2>=mid+1)
{
while(p1>=l&&opt[p1].x>=opt[p2].x)
{
if(opt[p1].ty==2){--p1;continue;};
insert1(opt[p1].y,opt[p1].x-opt[p1].y);
insert2(ed-opt[p1].y,opt[p1].x+opt[p1].y);
--p1;
}
if(opt[p2].ty==1) {--p2;continue;}
opt[p2].ans=min_(opt[p2].ans,min_(-opt[p2].x-opt[p2].y+query2(ed-opt[p2].y),-opt[p2].x+opt[p2].y+query1(opt[p2].y)));
--p2;
}
for(int i=mid;i>p1;i--) if(opt[i].ty==1) clear(opt[i].y);
sort(opt+l,opt+r+1,cmp_t);
cdq(mid+1,r);
return;
}
int main()
{
n=read();
m=read();
memset(tre1,0x3f,sizeof(tre1));
memset(tre2,0x3f,sizeof(tre2));
for(int i=1;i<=n;i++) ++num,opt[num]=(opt_){1,num,read(),read(),inf};
for(int i=1;i<=m;i++) ++num,opt[num]=(opt_){read(),num,read(),read(),inf};
cdq(1,num);
for(int i=1;i<=num;i++)
if(opt[i].ty==2)
printf("%d\n",opt[i].ans);
return 0;
}
简单题
离线版的就是mokia
在线版的可以用这个过掉