poj 1990 树状数组(耳背的牛谈话)poj2231

题意:一群耳背的牛,每头牛有一个音量阈值xi。当两头牛i,j交流的时候,交流的最小声音为max{x[i],x[j]}*他们之间的距离。现在有n头牛,求他们之间两两交流最少要的音量和。

思路:n的大小为20000显然不要n^2的算法。思路为首先按照阈值x对牛排序。那么新顺序下两头牛交流他们的max{x[i],x[j]}必为后面的牛的阈值,接下来就是快速求出当前牛和排在它前面所有牛的距离之和。需要用到两个树状数组,一个存放牛在特定距离的个数,另一个存放距离值。细节见代码。


poj2231:依然是牛之间谈话,但是比1990简单。a对b说话,音量必须等于两点之间的距离,问两两之间谈话的总音量。题目抽象相当于给出直线上n个点,求n(n-1)点对之间的距离之和。做法:先排序,然后从左到右一个一个求每个点到其左边点集的距离之和。维护一个1~k的下标之和即可。需要注意中间计算会不会超过int,如果超,勿忘强制转换。


1990代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
#define N 20005
long long t1[N],t2[N];
struct point{
    int id,x;
}p[N];
int n;
int cmp(struct point a,struct point b){
    return a.x < b.x;
}
int lowbit(int x){
    return x&(-x);
}
void add(long long* tree,int i,int x){
    for(int j = i;j<=N-5;j+=lowbit(j))
        tree[j] += x;
}
long long sum(long long* tree,int i){
    long long res = 0;
    for(int j = i;j>=1;j-=lowbit(j))
        res += tree[j];
    return res;
}
int main(){
    int i;
    long long res = 0,j;
    clc(t1, 0);
    clc(t2, 0);
    scanf("%d",&n);
    for(i = 1;i<=n;i++)
        scanf("%d %d",&p[i].x,&p[i].id);
    sort(p+1,p+1+n,cmp);
    
    add(t1,p[1].id,1);//t1是个数
    add(t2,p[1].id,p[1].id);//t2是距离
    for(i = 2;i<=n;i++){
        j = 0;
        j += sum(t1,p[i].id-1)*p[i].id-sum(t2,p[i].id-1);//牛i与之前距离号小于它的所有牛的距离差之和
        j += sum(t2,N-5)-sum(t2,p[i].id)-(sum(t1,N-5)-sum(t1,p[i].id))*p[i].id;//牛i与之前距离号大于它的所有牛的距离差之和
        res += j*p[i].x;
        add(t1,p[i].id,1);
        add(t2,p[i].id,p[i].id);
    }
    printf("%lld\n",res);
}

2231:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
#define N 10005
int s[N];
int n;
int main(){
    int i;
    long long j,res=0;
    scanf("%d",&n);
    for(i = 0;i<n;i++)
        scanf("%d",&s[i]);
    sort(s,s+n);
    j = s[0];
    for(i = 1;i<n;i++){
        res += (long long)s[i]*i - j;
        j += s[i];
    }
    printf("%lld\n",res<<1);
}


你可能感兴趣的:(poj 1990 树状数组(耳背的牛谈话)poj2231)