洛谷P3810 三维偏序 cdq分治模板题

博主在做洛谷P3810题时,发现昨天写的hdu模板题代码可能有误。在CDQ算法中,排序后相等的点可能不相邻,应先去重再进行程序。hdu题数据不强,后续会将去重的正确写法更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接:https://www.luogu.org/problemnew/show/P3810


思路:写这题时发现昨天写hdu那个模板题的板子可能是不对的,对于相等的两个点应该先去重再进行程序,因为cdq中排序结束后相等的点出来时不一定是紧挨着的了,所以再用之前的写法是可能出错的,不过hdu那题的数据好像不是很强,加个去重理解也很简单,待会会把hdu那题去重的正确写法改上去的。

AC代码:

#include<bits/stdc++.h>
#define INF 0x3F3F3F3F
#define endl '\n'
#define pb push_back
#define css(n) cout<<setiosflags(ios::fixed)<<setprecision(n); 
#define sd(a) scanf("%d",&a)
#define sld(a) scanf("%lld",&a)
#define m(a,b) memset(a,b,sizeof a)
#define p_queue priority_queue
using namespace std;
typedef long long ll;
const int maxn=100005;
const int maxm=200005;
int n,m,k;
int n1;
int t;
double a,b;
struct node
{
    int x,y,z;
    int id;
    int sum;
    int num;
 }dian[maxn],p1[maxn];
bool comp1(node a,node b)
{
 	if(a.x!=b.x) return a.x<b.x;
 	if(a.y!=b.y) return a.y<b.y;
 	return a.z<b.z;
}
bool comp2(node a,node b)
{
	if(a.y!=b.y)
    return a.y<b.y;
    return a.z<b.z;
}

int tre[maxm];
int N;
int lowbit(int x)
{
    return x&(-x);
}
void add(int pos,int val)
{
    while(pos<=N)
    {
        tre[pos]+=val;
        pos+=lowbit(pos);
    }
}
int ask(int pos)
{
    int ans=0;
    while(pos)
    {
        ans+=tre[pos];
        pos-=lowbit(pos); 
    }
    return ans;
 } 

void cdq(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1;
    cdq(l,mid),cdq(mid+1,r);
    sort(p1+l,p1+mid+1,comp2);//sort的第二个参数是结束的地址+1 
    sort(p1+mid+1,p1+r+1,comp2);
    int j=l;
    for(int i=mid+1;i<=r;i++)
    {
        for(;j<=mid;j++)
        {
            if(p1[j].y>p1[i].y) break;
         	add(p1[j].z,p1[j].num);
        }
        p1[i].sum+=ask(p1[i].z);
    }
    for(int zz=l;zz<=j-1;zz++)
    {
    	add(p1[zz].z,-p1[zz].num);
	}
   /* for(j=j-1;j>=l;j--)
    {
        add(dian[j].z,-1);
    }*/
}
int num[maxm]={0};
int main()
{
    sd(n);
    sd(k);
    N=k;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&dian[i].x,&dian[i].y,&dian[i].z);
        dian[i].id=i;
        dian[i].sum=0;
    }
    sort(dian+1,dian+1+n,comp1);
    n1=1;
    for(int i=1;i<=n;)
    {
    	int j=i;
    	int c=0;
    	while(j<=n)
    	{
    		if(dian[j].x==dian[i].x&&dian[j].y==dian[i].y&&dian[j].z==dian[i].z)
    		{
    			c++;
    			j++;
			}
			else break;
		}
		p1[n1]=dian[i];
		p1[n1].num=c;
		n1++;
		i=j;
	}
	n1--;
    cdq(1,n1);
    int i=1;
   // int mxx=0;
    int j; 
    
/*	for(int i=1;i<=n;i++)
    {
        cout<<dian[i].id<<"---"<<dian[i].x<<",,,"<<dian[i].sum<<endl; 
    }*/
    for(int i=1;i<=n1;i++)
    {
    	num[p1[i].sum+p1[i].num-1]+=p1[i].num;
	}
    for(int i=0;i<n;i++)
    {
        printf("%d\n",num[i]);
    }
    return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值