[poj] 1990 MooFest

原题

树状数组裸题

两个奶牛之间的贡献是max(v[i],v[j])和dis的和,因为如果一个个比较v[i],v[j]很麻烦,所以我们考虑按val排序加入,每加入就对已经在队列里的牛添加贡献,这样在添加的过程中就完成了答案的计算。
那么怎么在添加过程中计算距离呢?我们维护一个树状数组,记录到这个位置为止,pos之和是多少,这样在i位置插入一只牛,所产生的距离就是(排在前面的牛×i-排在前面的牛的距离和+排在后面的牛的距离和-排在后面的牛×i)×我的val,所以我们还要维护一个记录cnt的树状数组。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 20010
using namespace std;
int n,mx;
long long ans;
struct hhh
{
    int val,pos;
    bool operator < (const hhh &b) const
	{
	    if (val==b.val) return pos<b.pos;
	    return val<b.val;
	}
}a[N];
struct hh
{
    long long b[N];
    hh() { memset(b,0,sizeof(b)); }
    void modify(int p,int y)
	{
	    while (p<=mx)
	    {
		b[p]+=y;
		p+=p&-p;
	    }
	}
    long long query(int x)
	{
	    long long ans=0;
	    while (x)
	    {
		ans+=b[x];
		x-=x&-x;
	    }
	    return ans;
	}
}dis,cnt;

int read()
{
    int ans=0,fu=1;
    char j=getchar();
    for (;(j<'0' || j>'9') && j!='-';j=getchar()) ;
    if (j=='-') j=getchar(),fu=-1;
    for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
    return ans*fu;
}

int main()
{
    n=read();
    for (int i=1;i<=n;i++)
    {
	a[i].val=read();
	a[i].pos=read();
	mx=max(mx,a[i].pos);
    }
    sort(a+1,a+n+1);
    for (long long i=1,m,k,o,p;i<=n;i++)
    {
	m=cnt.query(a[i].pos-1);
	k=cnt.query(mx);
	o=dis.query(a[i].pos-1);
	p=dis.query(mx);
	ans+=(m*a[i].pos-o)*a[i].val+(p-o-(k-m)*a[i].pos)*a[i].val;
	cnt.modify(a[i].pos,1);
	dis.modify(a[i].pos,a[i].pos);
    }
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/mrha/p/7890579.html