三维偏序 cdq

luogu_3810

就是将逆序对转化到了三维上去

原理等我寒假再补

第一维sort解决

第二维并归排序(cdq)解决

第三维树状数组

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using std::sort;

const int maxn=101000;
const int Max=201000;

struct node
{
    int a,b,c;
    int size,ans;
    bool operator <= (const node &A)
    {
        if(b!=A.b)  return b<=A.b;
        if(c!=A.c)  return c<=A.c;
        return c<=A.c;
    }
};

node Q[maxn],tmp[maxn];
int base[Max],t[Max],len,Tim;
int TOT[Max<<1];
int n,m;

void add(int pos,int val,int T)
{
    while(pos<=len)
    {
        if(t[pos]!=T)
        {
            t[pos]=T;
            base[pos]=0;
        }
        base[pos]+=val;
        pos+=(pos&(-pos));
    }
    return ;
}

int sum(int pos,int T)
{
    int res=0;
    while(pos)
    {
        if(t[pos]!=T)
        {
            t[pos]=T;
            base[pos]=0;
        }
        res+=base[pos];
        pos-=(pos&(-pos));
    }
    return res;
}

bool compare(const node &a,const node &b)
{
    if(a.a!=b.a)    return a.a<b.a;
    if(a.b!=b.b)    return a.b<b.b;
    return a.c<b.c;
}

void cdq(int l,int r)
{
    if(l==r)    return ;
    int mid=(l+r)>>1,o=0,T=++Tim;
    cdq(l,mid);cdq(mid+1,r);
    int q=l,p=mid+1;
    while(q<=mid&&p<=r)
    {
        if(Q[q]<=Q[p])//按照第二维顺序,左区间的元素算贡献(利用bit),右区间的元素进行第三维元素的顺序对查询
        {
            add(Q[q].c,Q[q].size,T);//利用时间戳
            tmp[o++]=Q[q++];//回收元素
        }
        else
        {
            Q[p].ans+=sum(Q[p].c,T);
            tmp[o++]=Q[p++];
        }
    }
    while(q<=mid)   tmp[o++]=Q[q++];//将没有处理的元素压回tmp
    while(p<=r)
    {
        Q[p].ans+=sum(Q[p].c,T);
        tmp[o++]=Q[p++];
    }
    for(int i=0;i<o;i++)    Q[l+i]=tmp[i];//回填
    return ;
}

int main()
{
    scanf("%d%d",&n,&m);
    len=m;
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&tmp[i].a,&tmp[i].b,&tmp[i].c);
    sort(tmp+1,tmp+1+n,compare);//解决第一位顺序
    int T=0;
    for(int i=1,pas=1;i<=n;i++)//去重,cdq无法正确处理相同原元素
    {
        if(tmp[i].a!=tmp[i+1].a||tmp[i].b!=tmp[i+1].b||tmp[i].c!=tmp[i+1].c)
        {
            Q[++T]=tmp[i];
            Q[T].size=pas;Q[T].ans=0;
            pas=1;
        }
        else    pas++;
    }
    cdq(1,T);
    for(int i=1;i<=T;i++)   TOT[Q[i].ans+Q[i].size-1]+=Q[i].size;
    for(int i=0;i<n;i++)   printf("%d\n",TOT[i]);
}

原文地址:https://www.cnblogs.com/Lance1ot/p/10271917.html

时间: 2024-10-08 21:40:10

三维偏序 cdq的相关文章

BZOJ 3295:[Cqoi2011]动态逆序对(三维偏序 CDQ分治+树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=3295 题意:简单明了. 思路:终于好像有点明白CDQ分治处理三维偏序了.把删除操作看作是插入操作,那么可以按照插入的时间顺序看作是一维x,插入的数在原本序列的下标是一维y,插入的数本身是一维z.那么问题可以转化成每插入一个数(xx,yy,zz),求有多少个数(x,y,z)使得 x < xx,y < yy,z > zz .一开始先对 x 进行排序,然后进行CDQ分治.这样可以干掉一维,保证随

BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]

Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb.显然,两朵花可能有同样的属性.需要统计出评出每个等级的花的数量. Input 第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值. 以下N行,每

HDU 5618:Jam&#39;s problem again(CDQ分治+树状数组处理三维偏序)

http://acm.hdu.edu.cn/showproblem.php?pid=5618 题意:-- 思路:和NEUOJ那题一样的.重新写了遍理解了一下,算作处理三维偏序的模板了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #d

SPOJ LIS2 Another Longest Increasing Subsequence Problem 三维偏序最长链 CDQ分治

Another Longest Increasing Subsequence Problem Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=19929 Description Given a sequence of N pairs of integers, find the length of the longest incre

【算法】CDQ分治 -- 三维偏序 &amp; 动态逆序对

初次接触CDQ分治,感觉真的挺厉害的. 整体思路即分而治之,再用之前处理出来的答案统计之后的答案. 大概流程是: 对于区间 l ~ r : 1.处理 l ~mid, mid + 1 ~ r 的答案 2.分别排序规整 3.计算 l ~ mid 中每一个数对 mid + 1 ~ r 中的答案的贡献, 累加 4.得到区间l ~ r的答案 CDQ分治我一共也才做了两道题目, 就一起整理在这里了.大体都差不多,CDQ+树状数组分别维护两个维度. 1.三维偏序 #include <bits/stdc++.h

BZOJ3262/洛谷P3810 陌上花开 CDQ分治 三维偏序 树状数组

原文链接http://www.cnblogs.com/zhouzhendong/p/8672131.html 题目传送门 - BZOJ3262 题目传送门 - 落谷P3810 题意 有$n$个元素,第$i$个元素有$a_i$.$b_i$.$c_i$三个属性,设$f(i)$表示满足$a_j\leq a_i$且$b_j\leq b_i$且$c_j\leq c_i$的$j$的数量.对于$d\in [0,n)$,求$f(i)=d$的数量. $n\leq 100000,max\{a_i,b_i,c_i|i

三维偏序:CDQ分治

cdq分治是一种常用的降维手段,可以解决偏序问题. 题目 给定$n$个三元组$(x, y, z)$,给定一个$f(a)$,表示所有元素$b$(自己不算),它的$x,y,z$均小于等于$a$的对应$x,y,z$,求$[0, n)$中每种$f$值的个数. $n \leq 100000$ $x, y, z \leq 200000$ 简单模型 一维:仅有$x$:按$x$排序即可. 二维:有$(x, y)$,按先$x$后$y$顺序排序,然后将$y$值用树状数组统计. 三维偏序:cdq分治解法 思想:类似归

CDQ分治 三维偏序

这应该是一道CDQ分治的入门题目 我们知道,二维度的偏序问题直接通过,树状数组就可以实现了,但是三维如何实现呢? 我记得以前了解过一个小故事,应该就是分治的. 一个皇帝,想给部下分配任务,但是部下太多,他也无从下手于是他这个任务分给宰相,宰相也不怎么清楚,于是他又分给他的手下,这么一直分啊分啊,分到每一个人头顶上的时候 每个人知道自己要干什么,于是他把它的信息交给他的上级,上级有了这些数据后,他处理了交给他的上级...这么一直交啊...国王最后成功的分配这些任务. CDQ分治也是一样,在这里,首

P3157 [CQOI2011]动态逆序对 (CDQ解决三维偏序问题)

P3157 [CQOI2011]动态逆序对 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. 输入格式 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. 输出格式 输出包含m行,依次为删除每个元素之前,逆序对的个数. 输入输出样例 输入