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

在线版的可以用这个过掉

posted @ 2021-10-08 17:03  sitiy  阅读(32)  评论(0编辑  收藏  举报