CF 12D BALL 线段树 && 树状数组

http://codeforces.com/problemset/problem/12/D

线段树

View Code
#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

const int inf = ~0u>>2;

const int N = 500010;

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

int Max[N<<2];

struct node{

    int x,y,z;

}in[N];

int tot,n;

int num[N];

int max(int a,int b){

    return a>b?a:b;

}

void pushup(int rt){

    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);

}

void build(int l,int r,int rt){

    Max[rt]=0;

    if(l==r) return ;

    int m=(l+r)>>1;

    build(lson);

    build(rson);

}

void update(int p,int val,int l,int r,int rt){

    if(l==r){

        if(val>Max[rt])

            Max[rt]=val;

        return ;

    }

    int m=(l+r)>>1;

    if(p<=m) update(p,val,lson);

    else update(p,val,rson);

    pushup(rt);

}

int query(int L,int R,int l,int r,int rt){

    if(L<=l&&r<=R)      return Max[rt];

    int m=(l+r)>>1;

    int ret=0;

    if(L<=m) ret=max(ret,query(L,R,lson));

    if(R>m) ret=max(ret,query(L,R,rson));

    return ret;

}

void init(){

    sort(num+1,num+n+1);

    tot=unique(num+1,num+n+1)-num-1;

    build(1,tot,1);

    for(int i=1;i<=n;i++)

        in[i].x=lower_bound(num+1,num+1+tot,in[i].x)-num;

}

inline int cmp(node a,node b){

    return a.y>b.y;

}

int main()

{

    int i,j,k;

    scanf("%d",&n);

    for(i=1;i<=n;i++) {scanf("%d",&in[i].x);    num[i]=in[i].x;}

    for(i=1;i<=n;i++) scanf("%d",&in[i].y);

    for(i=1;i<=n;i++) scanf("%d",&in[i].z);

    init();

    sort(in+1,in+n+1,cmp);

    int ans=0;

    for(i=1;i<=n;i=j){

        for(j=i;j<=n&&in[j].y==in[i].y;j++){

            int z;

            z=query(in[j].x+1,tot,1,tot,1);

            if(z>in[j].z) ans++;

        }

        for(;i<=j-1;i++)

            update(in[i].x,in[i].z,1,tot,1);

    }

    printf("%d\n",ans);

    return 0;

}

/*

3

1 3 5

2 4 6

3 5 7

*/

 

树状数组

View Code
/*

CF  12D

树状数组好题

给你n个整数三元组,

对于某个三元组,判断是否存在一个三元组的元素都大于这个三元组

题目给三个数,必然有其道理

可以把其中一个数离散化当做树状数组的下标,再按照另外某个数排序

最后就只需利用树状数组数组处理好最后一个数就行了



具体做法:

比如对x离散化   对y降序排序   

x当做树状数组的下标

每次把y值相同的三元组一起拿出来处理

因为前面加进树状数组的数的y值肯定比现在这个数的y值要大,这一个数就不必考虑了

然后就是找前面加进树状数组的数中有没有z坐标 大于 当前枚举的数的z坐标,当然是在大于x的区间内

这里与树状数组的功能相反了,这里树状数组是求前n项中的最大值,而题目要求下标在x->n间的最大值

转换一下就好了

离散化前:1 3 5 7 9

离散化后并不是1 2 3 4 5

要倒过来:5 4 3 2 1

那么小于x的区间实际上就是大于x的区间

*/

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

const int N = 500010;

int c[N];

int num[N];

int n;

struct node{

    int x,y,z;

}in[N];

inline void Max(int &a,int b){

    if(a<b) a=b;

}

void update(int x,int d){

    for(;x<N;x+=x&-x)    Max(c[x],d);

}

int sum(int x){

    int ans=0;

    for(;x>0;x-=x&-x)    Max(ans,c[x]);

    return ans;

}

void init(){

     sort(num+1,num+n+1);

     int tot=unique(num+1,num+n+1)-num-1;

     for(int i=1;i<=n;i++)

         in[i].x=tot-(lower_bound(num+1,num+1+tot,in[i].x)-num-1);

     //把x的相对大小倒了过来  所以小于in[i].x实际表示大于in[i].x;,便于树状数组的sum操作

}

inline int cmp(node a,node b){

    return a.y>b.y;

}

int main()

{

    int i,j,k;

    scanf("%d",&n);

    for(i=1;i<=n;i++) {scanf("%d",&in[i].x);    num[i]=in[i].x;}

    for(i=1;i<=n;i++) scanf("%d",&in[i].y);

    for(i=1;i<=n;i++) scanf("%d",&in[i].z);

    init();

    memset(c,0,sizeof(c));

    sort(in+1,in+n+1,cmp);

    int ans=0;

    for(i=1;i<=n;i=j){

        for(j=i;j<=n&&in[j].y==in[i].y;j++){

            int z=sum(in[j].x-1);

            if(z>in[j].z) ans++;

        }

        for(;i<=j-1;i++)

            update(in[i].x,in[i].z);

    }

    printf("%d\n",ans);

    return 0;

}

/*

3

1 3 5

2 4 6

3 5 7

*/

你可能感兴趣的:(树状数组)