树状数组

3 篇文章 0 订阅
3 篇文章 0 订阅

POJ 2299 Ultra-QuickSort
题目链接:Ultra-QuickSort

Solution
由于数组元素各不相同且最大的可能到999,999,999 ,先将n个元素的数组元素转换为1-n的某个排列,
该排列与原数组各元素对应位置各元素相对大小关系一致,然后对其求逆序对个数即得答案,我用的树状数组版。

Code
树状数组版:

#include <cstdio>  
#include <cstring>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;  
#define N 500001
int a[N+2],c[N+2],n,order[N+1];  
struct node
{
    int key;
    int id;
    bool const operator<(const struct node& a)const
    {
        return key<a.key;
    }
} data[N+2];
inline int lowbit(int i){
    return i&(-i);
}
inline int sum(int i)
{
    int ans=0;
    for(;i>0;i-=lowbit(i))
        ans+=c[i];
    return ans;
}
inline void add(int i,int v)
{
    for(;i<=n;i+=lowbit(i))
        c[i]+=v;
}
int main()  
{  
    while(~scanf("%d",&n)&&n){
        memset(c,0,sizeof(c));
        long long ans=0;
        for(int i=1; i<=n; i++)
        {
            cin>>data[i].key;
            data[i].id=i;
        }
        sort(data+1,data+n+1);
        for(int i=1;i<=n;++i)
            order[data[i].id]=i;
        for(int i=1; i<=n;i++)
        {
            add(order[i],1);
            ans+=i-1-sum(order[i]-1);
        }
        cout<<ans<<endl;
    }
    return 0;  
}

嗯 刚学树状数组,再接着补。

HDU 3874 Necklace
题目链接:
Necklace

Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Description
大意是说有一串珠子,每个珠子都有自己的欣赏值value,(0<=value<=1e6)现在给你一串珠子每个的欣赏值,
并给出一些询问,查询某个区间总欣赏值是多少,但是一个约定就是如果这个区间内部有两个珠子的欣赏值是
一样的,那么他们就视为一个,即相同值只计算一次。

Code

#include <cstdio>  
#include <cstring>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long  
const int N=5e4;
const int M=2e5;
const int mmax=1e6;
int a[N+2],n,m;
int first[mmax+2];//存放value值第一次出现的位置
ll c[N+2],ans[M+2];//ans存放每次询问的答案  
struct node
{
    int l,r;
    int id;
    bool const operator<(const struct node& a)const
    {
        return r<a.r; //将询问按右端点由小到大排列
    }
}query[M+2];
inline int lowbit(int i){
    return i&(-i);
}
inline ll sum(int i)
{
    ll ans=0;
    for(;i>0;i-=lowbit(i))
        ans+=c[i];
    return ans;
}
inline void add(int i,int v)
{
    for(;i<=n;i+=lowbit(i))
        c[i]+=v;
}
int main()  
{  
    int t;
    scanf("%d",&t);
    getchar();
    while(t--){
        scanf("%d",&n);
        memset(c,0,sizeof(c));
        memset(first,0,sizeof(first));
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            if(!first[a[i]])
                first[a[i]]=i;
            add(i,a[i]);
        }
        scanf("%d",&m);
        for(int i=1;i<=m;++i){
             scanf("%d%d",&query[i].l,&query[i].r);
             query[i].id=i;
        }
        sort(query+1,query+m+1);
        int r=1;
        for(int i=1; i<=m;i++)
        {
            for(int j=r;j<=query[i].r;++j){
                if(first[a[j]]!=j){
                    add(first[a[j]],-a[j]);//加负值, 将之前出现过的value值减去
                    first[a[j]]=j;
                }
            }
            r=query[i].r;
            ans[query[i].id]=sum(query[i].r)-sum(query[i].l-1);
        }
        for(int i=1;i<=m;++i)
            printf("%I64d\n",ans[i]);
    }
    return 0;  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值