OpenJ_Bailian - 2352 Stars(线段树/树状数组)

题目链接

题意:统计几级星的个数,对每个星星来说,有多少x,y都不超过他的星星,他就是几级星(不包括自身);

题目给的星星是按y升序,y相等的时候x升序给出的,所以只需要知道每个星星前面有多少个x不超过他的就行;

很容易想到O(n2)的算法,但时间复杂度太高;

这里用线段树或者树状数组,每次输入一次查询一次x,在更新一次x;

用v表示结果,用t表示每个区间每个区间有多少个x的坐标;

线段树:

#include<cstdio>
#include<iostream>
using namespace std;

const int maxn=32000+10;//x,y的最大值
int t[maxn<<2],v[maxn];
int ans,n,x,y;

void query(int l,int r,int rt){//查询x前面有多少个星星
    if(x>=r) ans += t[rt];
    else if(x<l) return;
    else{
        int mid = (l+r)>>1;
        query(l,mid,rt<<1);
        query(mid+1,r,rt<<1|1);
    }
}

void update(int l,int r,int rt){//更新x所在的所有区间,l=r的时候是找到了子节点
    if(l==r){
        t[rt]++;
        return;
    }
    int mid = (l+r)>>1;
    if(x<=mid) update(l,mid,rt<<1);
    else update(mid+1,r,rt<<1|1);
    t[rt]++;
}

int main()
{
    cin>>n;
    for(int i = 0;i < n;i++){
        cin>>x>>y;//输入一个操作一次
        ans = 0;//ans是记录前面有多少星
        query(0,maxn,1);
        v[ans]++;
        update(0,maxn,1);
    }
    for(int i = 0;i < n;i++)
        cout<<v[i]<<endl;
    return 0;
}

树状数组:

#include<cstdio>
#include<iostream>
using namespace std;

const int maxn=32000+10;
int t[maxn],v[maxn];
int ans,n,x,y;

int lowbit(int x){//查找最低位的1
    return x&(-x);
}

int query(int x){//查询前x的和
    int ans = 0;//ans是结果
    while(x>0){//直到x减到0为止
        ans += t[x];//ans每次加上当前的值
        x -= lowbit(x);//x减去当前最低位的1
    }
    return ans;
}

void update(int x){//更新x的值
    while(x<=maxn){直到x增加到最大值
        t[x]++;//当前区间加一
        x += lowbit(x);//加上最低位的1
    }
    return;
}

int main()
{
    cin>>n;
    for(int i = 0;i < n;i++){
        cin>>x>>y;
        x++;//防止x是0时的陷阱,最后统计每个级别的星的数量,不会影响那个结果
        v[query(x)]++;
        update(x);
    }
    for(int i = 0;i < n;i++)
        cout<<v[i]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42754600/article/details/81914015