返回顶部

CDQ分治

image

P3810 【模板】三维偏序(陌上花开)

CDQ模板题,考虑先按\(a\)排序,减掉一位,然后再\(CDQ\)分治一维,用树状数组维护最后一维
还有本题特殊,去重操作不要忘记

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
#define pb push_back
using namespace std;
const int N = 2E5+5;
int n,k;
struct Bit
{
	int c[N];
	int lowbit(int x){return (x&(-x));}
	void add(int x,int val)
	{
		while(x<=k)
		{
			c[x]+=val;
			x+=lowbit(x);
		}
	}
	int ask(int x)
	{
		int ans=0;
		while(x)
		{
			ans+=c[x];
			x-=lowbit(x);
		}
		return ans;
	}
}T;
struct ac
{
	int a,b,c,w,ans;
}a[N],b[N];
int ans[N];
bool cmp(ac a,ac b)
{
	if(a.a==b.a)
	{
		if(a.b==b.b)
			return a.c<b.c;
		return a.b<b.b;
	}
	return a.a<b.a;
}
bool cmpy(ac a,ac b)
{
	if(a.b==b.b)
	{
		return a.c<b.c;
	}
	return a.b<b.b;
}
void cdq(int l,int r)
{
	if(l==r)return;
	int mid=(l+r)>>1;
	cdq(l,mid);cdq(mid+1,r);
	sort(b+l,b+mid+1,cmpy);sort(b+mid+1,b+r+1,cmpy);
	int i=mid+1,j=l;
	for(;i<=r;i++)
	{
		while(b[j].b<=b[i].b&&j<=mid)
			T.add(b[j].c,b[j].w),j++;
		b[i].ans+=T.ask(b[i].c);
	}
	for(int i=l;i<j;i++)
		T.add(b[i].c,-b[i].w);
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].a>>a[i].b>>a[i].c;
	}
	sort(a+1,a+1+n,cmp);
	int cnt=0,num=0;
	for(int i=1;i<=n;i++)
	{
		cnt++;
		if(a[i].a!=a[i+1].a||a[i].b!=a[i+1].b||a[i].c!=a[i+1].c)
			b[++num]=a[i],b[num].w=cnt,cnt=0;
	}
	cdq(1,num);
	for(int i=1;i<=num;i++)
	{
		ans[b[i].ans+b[i].w-1]+=b[i].w;
	}
	for(int i=0;i<n;i++)cout<<ans[i]<<endl;
	return 0;
}

关于优化,每次排个序太慢了
我们可以用归并排序,具体的就是把\(CDQ\)中两个排序去了,然后新开一个数组备用,然后调用\(merge\)函数,传\(5\)个参\(merge(l_1,r_1,l_2,r_2,num[])\)
就是把两个排过序的数组合并为一个排过序的数组

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
#define pb push_back
using namespace std;
const int N = 2E5+5;
int n,k;
struct Bit
{
    int c[N];
    int lowbit(int x){return (x&(-x));}
    void add(int x,int val)
    {
        while(x<=k)
        {
            c[x]+=val;
            x+=lowbit(x);
        }
    }
    int ask(int x)
    {
        int ans=0;
        while(x)
        {
            ans+=c[x];
            x-=lowbit(x);
        }
        return ans;
    }
}T;
struct ac
{
    int a,b,c,w,ans;
    friend bool operator < (const ac& a,const ac& b)
    {
        if(a.b==b.b)
        {
            return a.c<b.c;
        }
        return a.b<b.b;
    }
}a[N],b[N],q[N];
int ans[N];
bool cmp(ac a,ac b)
{
    if(a.a==b.a)
    {
        if(a.b==b.b)
            return a.c<b.c;
        return a.b<b.b;
    }
    return a.a<b.a;
}
bool cmpy(ac a,ac b)
{
    if(a.b==b.b)
    {
        return a.c<b.c;
    }
    return a.b<b.b;
}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)>>1;
    cdq(l,mid);cdq(mid+1,r);
    // sort(b+l,b+mid+1,cmpy);sort(b+mid+1,b+r+1,cmpy);
    int i=mid+1,j=l;
    for(;i<=r;i++)
    {
        while(b[j].b<=b[i].b&&j<=mid)
            T.add(b[j].c,b[j].w),j++;
        b[i].ans+=T.ask(b[i].c);
    }

    for(int i=l;i<j;i++)
        T.add(b[i].c,-b[i].w);
     merge(b+l,b+mid+1,b+mid+1,b+r+1,q+l);
     for(int i=l;i<=r;i++)b[i]=q[i];
}
int main()
{
    speed();
    // freopen("in.in","r",stdin);
    // freopen("out.out","w",stdout);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].a>>a[i].b>>a[i].c;
    }
    sort(a+1,a+1+n,cmp);
    int cnt=0,num=0;
    for(int i=1;i<=n;i++)
    {
        cnt++;
        if(a[i].a!=a[i+1].a||a[i].b!=a[i+1].b||a[i].c!=a[i+1].c)
            b[++num]=a[i],b[num].w=cnt,cnt=0;
    }
    for(int i=1;i<=num;i++)q[i]=b[i];
    cdq(1,num);
    for(int i=1;i<=num;i++)
    {
        ans[b[i].ans+b[i].w-1]+=b[i].w;
    }
    for(int i=0;i<n;i++)cout<<ans[i]<<endl;
    return 0;
}

P4390 [BalkanOI2007] Mokia 摩基亚

其实也是三维偏序,第一维时间,二三维\(x,y\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
// #pragma GCC optimize(3)
using namespace std;
const int N=2e6+6; 
int n,ans[N],w;
struct ac
{
	int tim,x,y,w,id;
}q[N];
bool cmp(ac a,ac b)
{
	if(a.x==b.x)return a.y<b.y;
	return a.x<b.x;
}
bool cmptim(ac a,ac b)
{
	return a.tim<b.tim;
}
struct Bit
{
	int c[N];
	int lowbit(int x){return x&-x;}
	void add(int x,int v)
	{
		while(x<=w)
		{
			c[x]+=v;
			x+=lowbit(x);
		}
	}
	int query(int x)
	{
		int ans=0;
		while(x)
		{
			ans+=c[x];
			x-=lowbit(x);
		}
		return ans;
	}
}T;
void cdq(int l,int r)
{
	if(l==r)return;
	// cout<<l<<" "<<r<<endl;
	int mid=(l+r)>>1;
	cdq(l,mid);cdq(mid+1,r);
	sort(q+l,q+mid+1,cmp);sort(q+mid+1,q+r+1,cmp);
	int i=mid+1,j=l;
	for(;i<=r;i++)
	{
		// cout<<i<<endl;
		while(q[j].x<=q[i].x&&j<=mid)
		{
			if(q[j].id==0)T.add(q[j].y,q[j].w);
			j++;
			// cout<<j<<" "<<mid<<endl;
		}
		if(q[i].id==1)q[i].w+=T.query(q[i].y);
	}
	for(int i=l;i<j;i++)
	{
		if(q[i].id==0)T.add(q[i].y,-q[i].w);
	}
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	int op,x,y,a,b;
	while(1)
	{
		cin>>op;
		if(!op)
		{
			cin>>w;
			w++;
		}else if(op==1)
		{
			cin>>x>>y>>a;
			++n;x++;y++;
			q[n]={n,x,y,a,0};
		}else if(op==2)
		{
			cin>>x>>y>>a>>b;
			a++;b++;
			q[++n]={n,x,y,0,1};
			q[++n]={n,a,b,0,1};
			q[++n]={n,x,b,0,1};
			q[++n]={n,a,y,0,1};
			// sort(q+1,q+1+n,cmp);
		}else if(op==3)break;
	}
	// cout<<"*****"<<endl;
	cdq(1,n);
	sort(q+1,q+1+n,cmptim);
	for(int i=1;i<=n;i++)
	{
		if(q[i].id)
		{
			cout<<q[i].w+q[i+1].w-q[i+2].w-q[i+3].w<<endl;
			i+=3;
		}
	}
	return 0;
}

P4169 [Violet] 天使玩偶/SJY摆棋子

我们可以转换为求四次\(cdq\),使点翻转分别在左上角左下角右上角右下角即可
注意判断\(l>r\)以及树状数组查询到\(0\)的情况

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N =1e6+5;
int n,m,ans[N];
int lx,rx,ly,ry;
struct ac
{
	int x,y,t;bool f;
	bool operator < (const ac& A)const
	{
		return x<=A.x;
	}
}a[N],p[N],q[N];
bool cmp(ac a,ac b)
{
	if(a.x==b.x)return a.y<b.y;
	return a.x<b.x;
}
struct Bit
{
	int c[N];
	int lowbit(int x){return x&-x;}
	inline void clear(int x)
	{
		if(!x)return;
		while(x<=ly)
		{
			if(c[x])c[x]=0;
			else break;
			x+=lowbit(x);
		}			
	}
	inline void add(int x,int v)
	{
		if(!x)
		{
			// c[0]=max(c[0],val);
			return;
		}
		while(x<=ly)
		{
			c[x]=max(v,c[x]);
			x+=lowbit(x);
		}
	}
	inline int query(int x)
	{
		if(!x)return 0;
		int ans=0;
		while(x)
		{
			// cout<<x<<endl;
			ans=max(c[x],ans);
			x-=lowbit(x);
		}
		return ans;
	}
}T;
inline void cdq(int l,int r)
{
	if(l>r)return;
	if(l==r)return;
	// cout<<l<<" "<<r<<endl;
	int mid=(l+r)>>1;
	cdq(l,mid);cdq(mid+1,r);
	// sort(p+l,p+1+mid,cmp);sort(p+mid+1,p+r,cmp);
	int i=mid+1,j=l;
	for(;i<=r;i++)
	{
		if(p[i].f)continue;
		while(p[j].x<=p[i].x&&j<=mid)
		{
			// cout<<j<<endl;
			if(p[j].f)T.add(p[j].y,p[j].y+p[j].x);
			j++;
		}
		int tmp=T.query(p[i].y);
		if(tmp)ans[p[i].t]=min(ans[p[i].t],p[i].x+p[i].y-tmp);
	}
	for(int i=l;i<j;i++)
		if(p[i].f)T.clear(p[i].y);

	merge(p+l,p+1+mid,p+mid+1,p+r+1,q+l);

	for (int i = l; i <= r; ++i) p[i] = q[i];
	// for(int i=l;i<=r;i++)
}
inline void Delete()
{
	rx=ry=m=0;
	for(int i=1;i<=n;i++)
	{
		if(!p[i].f)rx=max(rx,p[i].x),ry=max(ry,p[i].y);
	}
	for(int i=1;i<=n;i++)
		if(p[i].x<=rx&&p[i].y<=ry)q[++m]=p[i];
	for(int i=1;i<=m;i++)p[i]=q[i];
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>m;
	memset(ans,0x3f,sizeof ans);
	int k,x,y;
	for(int i=1;i<=n;i++)
	{
		cin>>x>>y;x++;y++;
		a[i]={x,y,i,1};
		lx=max(lx,x);ly=max(ly,y);
	}
	while(m--)
	{
		cin>>k>>x>>y;x++;y++;
		++n;a[n]={x,y,n,bool(k&1)};
		lx=max(lx,x);ly=max(ly,y);
	}
	++lx;++ly;
	for(int i=1;i<=n;i++)p[i]=a[i];
	Delete();cdq(1,m);
	for(int i=1;i<=n;i++)
		p[i]=a[i],p[i].x=lx-p[i].x;
	Delete();cdq(1,m);
	for(int i=1;i<=n;i++)
		p[i]=a[i],p[i].y=ly-p[i].y;
	Delete();cdq(1,m);
	for(int i=1;i<=n;i++)
		p[i]=a[i],p[i].x=lx-p[i].x,p[i].y=ly-p[i].y;
	Delete();cdq(1,m);
	for(int i=1;i<=n;i++)
		if(!a[i].f)cout<<ans[i]<<endl;
	return 0;
}
posted @ 2024-08-13 10:28  wlesq  阅读(12)  评论(0编辑  收藏  举报