P2345 奶牛集会

  这道题我感觉评成紫题并不夸张,这比某些紫题思维含量高多了……反正我好久才想明白怎么做……

  其实,这道题就是求这个式子所有的 “ max{ Vi ; Vj } × | Xi − Xj | ” 之和。由于n的范围20000,显然 n2是过不了的。(但是洛谷数据问题,n2能过,我也是醉了……)

  那我们分析一下:对于一对 i , j ,能做出贡献的只有大的 v 所以我们对于一个 v ,一定是找比 v 小的去累计贡献,所以我们要从小到大枚举 v 。

  那我们考虑对于这样的一个 v 的贡献:

  20000 ————B段———— v —————A段——— 1

  一下考虑都是小于 v 的其他 v ' 。

  对于A段和B段,我们发现想求贡献就需要知道A 、B段的距离和,和点的个数。这两个用线段树维护即可,那么我们的问题就在如何锁定 v ' 。

  其实这个很简答,在从小打到枚举 v 的同时处理线段树,这样我们每一次考虑的就是小于 v 的 v ' 了。

  这道题真的挺好,值得一做。

  北京市第三区交委提醒您:做题不long long,亲人两行泪。

  代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define maxn 80000
#define int long long
#define ls now<<1
#define rs now<<1|1
struct node
{
    int v,x;
} q[maxn];
int l[maxn],r[maxn],x[maxn],num[maxn];
int n,ans;
void up(int now)
{
    num[now]=num[ls]+num[rs];
    x[now]=x[ls]+x[rs];
}
bool cmp(node a,node b)
{
    return a.v<b.v;
}
void build(int now,int L,int R)
{
    l[now]=L;
    r[now]=R;
    if(L==R) return ;
    int mid=(L+R)>>1;
    build(ls,L,mid);
    build(rs,mid+1,R);
}
void update(int now,int id)
{
    if(l[now]==r[now]&&l[now]==id)
    {
        num[now]++;
        x[now]=id;
        return ;
    }
    int mid=(l[now]+r[now])>>1;
    if(id<=mid) update(ls,id);
    else update(rs,id);
    up(now);
}
int query_num(int now,int L,int R)
{
    if(l[now]==L&&r[now]==R)
        return num[now];
    int mid=(l[now]+r[now])>>1;
    if(R<=mid) return query_num(ls,L,R);
    else if(L>mid) return query_num(rs,L,R);
    else return query_num(ls,L,mid)+query_num(rs,mid+1,R);
}
int query_sum(int now,int L,int R)
{
    if(l[now]==L&&r[now]==R)
        return x[now];
    int mid=(l[now]+r[now])>>1;
    if(R<=mid) return query_sum(ls,L,R);
    else if(L>mid) return query_sum(rs,L,R);
    else return query_sum(ls,L,mid)+query_sum(rs,mid+1,R);
}
void solve()
{
    for(int i=1;i<=n;i++)
    {
        int x=q[i].x;
        int v=q[i].v;
        ans+=v*(query_num(1,1,x)*x-query_sum(1,1,x))
        +v*(query_sum(1,x,20000)-query_num(1,x,20000)*x);
        update(1,x);
    }
}
main()
{
    scanf("%lld",&n);
    for(int i=1; i<=n; i++)
        scanf("%lld%lld",&q[i].v,&q[i].x);
    sort(q+1,q+n+1,cmp);
    build(1,1,20000);
    solve();
    printf("%lld\n",ans);
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/popo-black-cat/p/10941105.html
今日推荐