POJ

来源:互联网 发布:古琴淘宝 编辑:程序博客网 时间:2024/06/04 23:29

题目大意:

有一排acm大牛(20,000),告诉你他们每个人的听力水平和所在位置坐标,并且他们每个人之间交流都需要的声音大小为:他们之间的距离乘他们两个人听力水平的较大值。现在问你每一对牛都交流一次,并且他们交流都是用的能交流的最小的声音,请算出他们这个活动产生的各种声音的大小的总和(应该是相同大小的声音多次出现分别都加上)。

分析:

至少要求出每两个牛交流产生的声音值20000(20001)/2=2108,这样就会产生这么多的值,然后用一个数组标记是否出现过,时间2108。这大概就是传说中的超时吧。
话说上面的也没用到树状数组啊,这怎么能行。再考虑一个问题,比如所需声音最大的和其他的所有牛交流一次,产生的声音的总和为:v[max](dis[1]+dis[2]+...+dis[n])(dis [ i ] 表示i距离max的距离)其中(dis[1]+dis[2]+...+dis[n])可以用树状数组求出。
具体的代码实现技巧就是,用两个树状数组,一个记录坐标和,一个记录个数。求一个点右面的和等于树状数组总和减这个点左面的和。

代码:

#include<iostream> #include<string.h>#include<math.h>#include<stdio.h>#include<algorithm>#define maxn 20500using namespace std;struct xcx{    int x;    int v;}cow[maxn];int n;long long int tree[3][maxn]={0};//tree[1]计算有多少个,tree[2]计算坐标和是多少 bool my_cmp(xcx x,xcx y){    return x.v<y.v;}int lowbit(int x){    return x&(-x);}void add(int x)//加上坐标为x的一个点 {    int t=x;    while(x<=maxn)    {        tree[1][x]+=1;        tree[2][x]+=t;        x+=lowbit(x);    }}long long int sum(int i,int x)//i=1求个数,i=2求坐标和 {    long long int s=0;    while(x>0)    {        s+=tree[i][x];        x-=lowbit(x);    }    return s;}int main(){    cin>>n;    for(int i=1;i<=n;i++)    {        scanf("%d%d",&cow[i].v,&cow[i].x);    }    sort(cow+1,cow+n+1,my_cmp);    /*for(int i=1;i<=n;i++)    {        cout<<cow[i].v<<endl;    }*/    long long int best=0;    for(int i=1;i<=n;i++)    {        long long int l,r;        l=sum(1,cow[i].x)*cow[i].x-sum(2,cow[i].x);        r=sum(2,maxn)-sum(2,cow[i].x)-(sum(1,maxn)-sum(1,cow[i].x))*cow[i].x;        best+=cow[i].v*(l+r);        //cout<<l<<" "<<r<<" "<<best<<endl;        add(cow[i].x);    }    cout<<best<<endl;}

后注:

这次完全自己思路,一次ac,爽~
注意回来要仔细研究一下离线处理的思想。

0 0
原创粉丝点击