线段树

Problem 1492 地震预测

Accept: 302    Submit: 1633
Time Limit: 1500 mSec    Memory Limit : 32768 KB

Problem Description

怀特先生是一名研究地震的科学家,最近他发现如果知道某一段时间内的地壳震动能量采样的最小波动值之和,可以有效地预测大地震的发生。

假设已知一段时间的n次地壳震动能量的采样值为a1,a2,…an,那么第i 次采样的最小波动值为min{|ai-aj| | i<j<=n},即第i 次采样的最小波动值是其后n-i次采样值与第i次采样值之差的绝对值中最小的值,特别地,第n次采样的最小波动值为an

请编写一个程序计算这n次采样的最小波动值之和。

Input

本题有多组输入数据,你必须处理到EOF为止

输入数据第一行有一个数n(1<=n<=105) ,表示采样的次数。

第二行有n个整数,表示n次地壳震动能量的采样值a1,a2,…an (0<=ai<=107 )。

Output

输出n次采样的最小波动值之和。

Sample Input

4
2 0 3 10

Sample Output

21
参考别人的思路做的,用到了线段树求和
View Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
//#include <cmath>
#define lowbit(x) x&(-x)

using namespace std;
const int maxn=100010;

int a[maxn],b[maxn],sum[maxn],k,tim[maxn];
bool flag[maxn];

void insert(int pos,int d)
{
    for(int i=pos;i<k;i+=lowbit(i))
      sum[i]+=d;
}
int query(int pos)
{
    int s=0;
    for(int i=pos;i>0;i-=lowbit(i))
      s+=sum[i];
    return s;
}
int bin(int key,int l,int r)
{
    int m;
    while(l<=r)
    {
        m=(l+r)>>1;
        if(b[m]==key) return m;
        else if(b[m]<key) l=m+1;
        else r=m-1;
    }
}
int bin1(int key,int l,int r)
{
    int m,ret=1;
    while(l<=r)
    {
        m=(l+r)>>1;
        int ss=query(m);
        if(ss>=key)
        {
            ret=m;r=m-1;
        }
        else l=m+1;
    }
    return ret;
}
int abs(int key)
{
    if(key>0) return key;
    return -key;
}
int main()
{
    int n,pos;
    while(scanf("%d",&n)==1)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+n+1);
        memset(sum,0,sizeof(sum));
        k=2;
        tim[1]=1;
        for(int i=2;i<=n;i++)
          if(b[i]!=b[i-1]) b[k++]=b[i],tim[k-1]=1;
          else tim[k-1]++;
        for(int i=1;i<k;i++)
          insert(i,tim[i]);
       // cout<<endl;
        long long ans=a[n];
       // cout<<ans<<endl;
        for(int i=1;i<n;i++)
        {
            int pos=bin(a[i],1,k-1);
            // cout<<pos<<" ";
            insert(pos,-1);
            int rank=query(pos);
           // cout<<rank<<" ";
            int Min=99999999;
            if(rank!=0)
            {
                int pos1=bin1(rank,1,k-1);
                Min=min(Min,abs(a[i]-b[pos1]));
            }
            if(rank!=n-i)
            {
                int pos2=bin1(rank+1,1,k-1);
                Min=min(Min,abs(a[i]-b[pos2]));
            }
            ans+=Min;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted on 2012-04-27 18:34  Goal  阅读(384)  评论(0编辑  收藏  举报

导航