陌上花开

传送门

关于CDQ的学习

毒瘤出题人,毁我青春,浪费了我一天时间!

首先,我们想到了树套树套树,代码十分(chang),于是并没人打算这么做。。。$$O(nlog^3n)$$
然后,又有人用了CDQ,一维排序,消除第一维的影响,二维归并,第三位用权值树状数组来统计答案。$$O(nlog^2n)$$
虽然这样确实可以,但是能尽量(装逼)少用就少用数据结构吧。。。
于是我们考虑CDQ套CDQ,没错,两层归并排序!$$O(nlog^2n)$$就是常数大了点$$......$$

无所谓啦,哈哈哈(尴尬不是礼节的微笑)
然后就A啦!
代码:

//这里我写了非递归的归并排序
#include<cstdio>
#include<cstring>
#include<algorithm>
using  namespace  std;
struct  node
{
    bool  bk;
    int  aa[4],id;
}a[210000],tmp[210000],tmpp[210000];int  n,m,sum,len[3],d[210000],b[210000];
bool  cmp(node  x,node  y){return  x.aa[1]<y.aa[1];}
void  rework2(int  l,int  mid,int  r)//统计答案
{
    len[2]=0;sum=0;
    int  ll=l,rr=mid+1;
    while(ll<=mid  &&  rr<=r)
    {
        if(tmp[ll].aa[3]<=tmp[rr].aa[3])
        {
            if(tmp[ll].bk==false)sum++;
            tmpp[++len[2]]=tmp[ll++];
        }
        else
        {
            if(tmp[rr].bk==true)d[tmp[rr].id]+=sum;
            tmpp[++len[2]]=tmp[rr++];
        }
    }
    while(ll<=mid)tmpp[++len[2]]=tmp[ll++];
    while(rr<=r)
    {
        if(tmp[rr].bk==true)d[tmp[rr].id]+=sum;
        tmpp[++len[2]]=tmp[rr++];
    }
    for(int  i=l;i<=r;i++)tmp[i]=tmpp[i-l+1];
}
void  work2()
{
    int  lenn=1;
    while(lenn<len[1])
    {
        int  x=1;
        while(x<=len[1]-(lenn<<1)-1)
        {
            rework2(x,x+lenn-1,x+(lenn<<1)-1);
            x+=(lenn<<1);
        }
        if(x+lenn<=len[1])rework2(x,x+lenn-1,len[1]);
        lenn*=2;
    }
}
void  rework1(int  l,int  mid,int  r)//第一次归并,不处理结果
{
    len[1]=0;
    int  ll=l,rr=mid+1;
    while(ll<=mid  &&  rr<=r)
    {
        if(a[ll].aa[2]<=a[rr].aa[2])tmp[++len[1]]=a[ll++],tmp[len[1]].bk=false;
        else  tmp[++len[1]]=a[rr++],tmp[len[1]].bk=true;
    }
    while(ll<=mid)tmp[++len[1]]=a[ll++],tmp[len[1]].bk=false;
    while(rr<=r)tmp[++len[1]]=a[rr++],tmp[len[1]].bk=true;
    for(int  i=l;i<=r;i++)a[i]=tmp[i-l+1];
}
void  work1()//非递归归并排序
{
    int  lenn=1;
    while(lenn<n)
    {
        int  x=1;
        while(x<=n-(lenn<<1)-1)
        {
            rework1(x,x+lenn-1,x+(lenn<<1)-1);
            work2();
            x+=(lenn<<1);
        }
        if(x+lenn<=n)/*x+len-1<n*/
        {
            rework1(x,x+lenn-1,n);
            work2();
        }
        lenn*=2;
    }
}
int  main()
{
    scanf("%d%d",&n,&m);
    for(int  i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a[i].aa[1],&a[i].aa[2],&a[i].aa[3]);
        a[i].id=i;//用于找到对应的位置
    }
    sort(a+1,a+n+1,cmp);
    work1();
    for(int  i=1;i<=n;i++)b[d[i]]++;//统计
    for(int  i=0;i<n;i++)printf("%d\n",b[i]);
    return  0;
}

开心

你觉得作者有这么好心给你正确的代码吗?,你觉得这符合出题人的审美吗,你觉得这么裸的题却这么少人出售烤main包夹小绿鸟很正常吗?

来自出题人的笑容

瞎扯完毕

于是,膜了好久的题解,终于懂了,╮(╯▽╰)╭。。。

一道不太对劲的点分治。。。点分治不是小于吗喂?啊啊啊啊啊!

绝望
没错,问题就出在了等于上面。

如:1,2,1与1,2,3有可能在第一次排序上变成了这样:(1,2,3)在(1,2,1)左边......

于是你修改了排序:

bool  cmp(node  x,node  y){return  x.aa[1]==y.aa[1]?(x.aa[2]==y.aa[2]?x.aa[3]<y.aa[3]:x.aa[2]<y.aa[2]):x.aa[1]<y.aa[1];}

但是:
绝望
哼
继续膜题解与寄刀片。。。

\[终于,功夫不负有心人,终于发现了错误! \]

由于可以等于,则会出现两个相同的三元组,由于CDQ的本质是左边影响右边,所以这两个三元组中预先将左边的三元组加上右边有多少相同的三元组。

如代码:

    sort(a+1,a+n+1,cmp);
    for(int  i=n;i>=2;i--)
    {
        if(a[i-1].aa[1]==a[i].aa[1]  &&  a[i-1].aa[2]==a[i].aa[2]  &&  a[i-1].aa[3]==a[i].aa[3])d[a[i-1].id]=d[a[i].id]+1;
    }

A了,真开心

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>别想了,想抄代码?
using  namespace  std;
struct  node
{
    bool  bk;
    int  aa[4],id;
}a[210000],tmp[210000],tmpp[210000];int  n,m,sum,len[3],d[210000],b[210000];
bool  cmp(node  x,node  y){return  x.aa[1]==y.aa[1]?(x.aa[2]==y.aa[2]?x.aa[3]<y.aa[3]:x.aa[2]<y.aa[2]):x.aa[1]<y.aa[1];}
void  rework2(int  l,int  mid,int  r)
{
    len[2]=0;sum=0;
    int  ll=l,rr=mid+1;
    while(ll<=mid  &&  rr<=r)
    {
        if(tmp[ll].aa[3]<=tmp[rr].aa[3])
        {
            if(tmp[ll].bk==false)sum++;哈哈,不存在的
            tmpp[++len[2]]=tmp[ll++];
        }
        else
        {
            if(tmp[rr].bk==true)d[tmp[rr].id]+=sum;
            tmpp[++len[2]]=tmp[rr++];
        }
    }
    while(ll<=mid)tmpp[++len[2]]=tmp[ll++];
    while(rr<=r)
    {
        if(tmp[rr].bk==true)d[tmp[rr].id]+=sum;
        tmpp[++len[2]]=tmp[rr++];
    }
    for(int  i=l;i<=r;i++)tmp[i]=tmpp[i-l+1];
}
void  work2()
{
    int  lenn=1;
    while(lenn<len[1])
    {
        int  x=1;
        while(x<=len[1]-(lenn<<1)-1)
        {
            rework2(x,x+lenn-1,x+(lenn<<1)-1);
            x+=(lenn<<1);
        }我无处不在
        if(x+lenn<=len[1])rework2(x,x+lenn-1,len[1]);
        lenn*=2;
    }
}
void  rework1(int  l,int  mid,int  r)
{
    len[1]=0;
    int  ll=l,rr=mid+1;
    while(ll<=mid  &&  rr<=r)
    {
        if(a[ll].aa[2]<=a[rr].aa[2])tmp[++len[1]]=a[ll++],tmp[len[1]].bk=false;
        else  tmp[++len[1]]=a[rr++],tmp[len[1]].bk=true;
    }
    while(ll<=mid)tmp[++len[1]]=a[ll++],tmp[len[1]].bk=false;
    while(rr<=r)tmp[++len[1]]=a[rr++],tmp[len[1]].bk=true;
    for(int  i=l;i<=r;i++)a[i]=tmp[i-l+1];
}
void  work1()
{
    int  lenn=1;
    while(lenn<n)
    {
        int  x=1;
        while(x<=n-(lenn<<1)-1)
        {惩戒那些抄代码的人
            rework1(x,x+lenn-1,x+(lenn<<1)-1);
            work2();
            x+=(lenn<<1);
        }
        if(x+lenn<=n)/*x+len-1<n*/
        {
            rework1(x,x+lenn-1,n);
            work2();
        }
        lenn*=2;
    }
}
int  main()
{
    scanf("%d%d",&n,&m);
    for(int  i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a[i].aa[1],&a[i].aa[2],&a[i].aa[3]);
        a[i].id=i;
    }
    sort(a+1,a+n+1,cmp);
    for(int  i=n;i>=2;i--)
    {
        if(a[i-1].aa[1]==a[i].aa[1]  &&  a[i-1].aa[2]==a[i].aa[2]  &&  a[i-1].aa[3]==a[i].aa[3])d[a[i-1].id]=d[a[i].id]+1;
    }
    work1();
    for(int  i=1;i<=n;i++)b[d[i]]++;
    for(int  i=0;i<n;i++)printf("%d\n",b[i]);
    return  0;
}抄就抄了,我不管了,CE不怪我
posted @ 2018-10-17 16:28  敌敌畏58  阅读(116)  评论(0编辑  收藏  举报