bzoj 3262 陌上花开

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3262

CDQ裸题。三维偏序。一眼看出一维排序、一维递归、一维树状数组。

可是有相等的怎么办?

然后看了TJ。https://blog.csdn.net/creationaugust/article/details/48788317

https://blog.csdn.net/clove_unique/article/details/54235339

其实分析一下:c的相等在树状数组里自己就能弄了;

  仅a相等:一开始排序的第二关键字是b,然后就没事了(递归中可以解决);

  仅b相等:毫无关系;

  a和b都相等:一开始排序的第二关键字是b的话,想一想发现只有最大的那个包含了所有,所以最后弄一弄就行了;

        或从一开始就找出所有a、b、c都相等的东西,记一个num。

注意树状数组的边界是m!!!

*先递归下去,再做本层的操作,本层的排序就不会对递归下去的东西造成影响。(当然也可以把本层的东西拿出来到别的数组里,对那个数组排序、操作)

  需要保证的是本层默认的:至少是mid左边的a一定小于mid右边的a。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=2e5+5;
int n,m,f[M],cnt[N],tot;
struct Node{
    int a,b,c,sum,num;
}t[N],s[N];
bool cmpb(Node x,Node y){return x.b<y.b;}
bool cmp(Node x,Node y){return x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c);}
bool check(Node x,Node y){return x.a==y.a&&x.b==y.b&&x.c==y.c;}
void add(int x,int v){for(;x<=m;x+=(x&-x))f[x]+=v;}  //x<=m!!!!!!!!!!!!
int query(int x){int ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=((l+r)>>1),p=l;
    cdq(l,mid);cdq(mid+1,r);
    sort(t+l,t+mid+1,cmpb);sort(t+mid+1,t+r+1,cmpb);    //sort左开右闭
    for(int i=mid+1;i<=r;i++)
    {
        while(p<=mid&&t[p].b<=t[i].b)add(t[p].c,t[p].num),p++;    //p<=mid!!!  //请不要把p++写在add里面 
        t[i].sum+=query(t[i].c);
    }
    for(int i=l;i<p;i++)add(t[i].c,-t[i].num);   //撤销
//  sort(t+l,t+mid+1,cmpa);sort(t+mid+1,t+r+1,cmpa);    //撤销 
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].c);
    sort(s+1,s+n+1,cmp);int ct;
    for(int i=1;i<=n;i++)
    {
        ct=1;
        while(check(s[i],s[i+1]))ct++,i++;
        t[++tot]=s[i];t[tot].num=ct;
    }
    cdq(1,tot);
    for(int i=1;i<=tot;i++)cnt[t[i].sum+t[i].num-1]+=t[i].num;
    for(int i=0;i<n;i++)printf("%d\n",cnt[i]);
    return 0;
}
View Code

当然也可以先做完本层的,再排序回去。不过会很慢。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=2e5+5;
int n,m,f[M],cnt[N];
struct Node{
    int a,b,c,sum,num;
}t[N];
bool cmpb(Node x,Node y){return x.b<y.b;}
bool cmp(Node x,Node y){return x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c);}
bool check(Node x,Node y){return x.a==y.a&&x.b==y.b&&x.c==y.c;}
void add(int x,int v){for(;x<=m;x+=(x&-x))f[x]+=v;}  //x<=m!!!!!!!!!!!!
int query(int x){int ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=((l+r)>>1),p=l;
    sort(t+l,t+mid+1,cmpb);sort(t+mid+1,t+r+1,cmpb);    //sort左开右闭
    for(int i=mid+1;i<=r;i++)
    {
        while(p<=mid&&t[p].b<=t[i].b)add(t[p].c,1),p++;   //p<=mid!!!  //请不要把p++写在add里面 
        t[i].sum+=query(t[i].c);
    }
    for(int i=l;i<p;i++)add(t[i].c,-1);  //撤销
    sort(t+l,t+mid+1,cmp);sort(t+mid+1,t+r+1,cmp);  //撤销 
    cdq(l,mid);cdq(mid+1,r);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&t[i].a,&t[i].b,&t[i].c);
    sort(t+1,t+n+1,cmp);int ct;
    cdq(1,n);
    for(int i=1;i<=n;i++)
    {
        ct=1;
        while(check(t[i],t[i+1]))ct++,i++;
        cnt[t[i].sum]+=ct;
    }
    for(int i=0;i<n;i++)printf("%d\n",cnt[i]);
    return 0;
}
View Code

十分奇怪的是为什么不记num,然后弄先递归下去的版本,就WA了?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=2e5+5;
int n,m,f[M],cnt[N];
struct Node{
    int a,b,c,sum,num;
}t[N];
bool cmpb(Node x,Node y){return x.b<y.b;}
bool cmp(Node x,Node y){return x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c);}
bool check(Node x,Node y){return x.a==y.a&&x.b==y.b&&x.c==y.c;}
void add(int x,int v){for(;x<=m;x+=(x&-x))f[x]+=v;}    //x<=m!!!!!!!!!!!!
int query(int x){int ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=((l+r)>>1),p=l;
    cdq(l,mid);cdq(mid+1,r);
    sort(t+l,t+mid+1,cmpb);sort(t+mid+1,t+r+1,cmpb);    //sort左开右闭
    for(int i=mid+1;i<=r;i++)
    {
        while(p<=mid&&t[p].b<=t[i].b)add(t[p].c,1),p++;    //p<=mid!!!    //请不要把p++写在add里面 
        t[i].sum+=query(t[i].c);
    }
    for(int i=l;i<p;i++)add(t[i].c,-1);    //撤销
//    sort(t+l,t+mid+1,cmp);sort(t+mid+1,t+r+1,cmp);    //撤销 
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&t[i].a,&t[i].b,&t[i].c);
    sort(t+1,t+n+1,cmp);int ct;
    cdq(1,n);
    sort(t+1,t+n+1,cmp);//
    for(int i=1;i<=n;i++)
    {
        ct=1;
        while(check(t[i],t[i+1]))ct++,i++;
        cnt[t[i].sum]+=ct;
    }
    for(int i=0;i<n;i++)printf("%d\n",cnt[i]);
    return 0;
}
View Code

 

posted on 2018-06-26 18:02  Narh  阅读(96)  评论(0编辑  收藏  举报

导航