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
*/
posted @ 2012-05-12 20:05  Because Of You  Views(418)  Comments(0Edit  收藏  举报