• Codeforces1311F. Moving Points (树状数组 离散化)


    https://codeforces.com/problemset/problem/1311/E

       题目点对追击问题可以抽象成两个一次函数相交问题,y = v*t+xi,xi为y轴上的截距,v是斜率,那么当且仅当两个函数在第一象限相交时,点对的最小距离是0,如果两个点对不在第一象限相交,则点对最小距离是就是y轴截距绝对值之差。

       可以轻易得到在第一象限相交的条件是,假设直线L1和L2,L1的斜率小于L2的斜率,L1的截距小于L2的截距时,两个直线在第一象限没有交点,其余情况均有交点。分别讨论这两种情况即可。

       首先离散化,把点的移动速度按从小打到排序一遍,并去重,再开一个结构体存贮点对信息,并按照截距大小排序。

       遍历结构体,用两个树状数组维护Vi,和Xi的前缀和,对于P[i]的速度Vi,在speed排序后的数组中查询Vi在speed数组中的位置pos,树状数组查询斜率比P[i]的斜率小的点个数,查询pos位置点的截距之和,那么P[i]对于答案的贡献就是:斜率比P[i]的斜率小的点个数×Xi(截距)- 斜率比P[i]小且截距比P[i]小的点的截距之和,每次把其贡献加入答案之后,在树状数组中去更新pos位置的点个数和和前缀和。

    AC代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 2e5+5;
     5 int n;
     6 ll c[maxn],c2[maxn]; 
     7 int lowbit(int x) {
     8   return x & -x;
     9 }
    10 void add(ll x, ll k) {
    11   while (x <= n) { 
    12     c[x] = c[x] + k;
    13     x = x + lowbit(x);
    14   }
    15 }
    16 void add2(ll x, ll k) {
    17   while (x <= n) { 
    18     c2[x] = c2[x] + k;
    19     x = x + lowbit(x);
    20   }
    21 }
    22 ll getsum(int x) {  
    23   ll ans = 0;
    24   while (x >= 1) {
    25     ans = ans + c[x];
    26     x = x - lowbit(x);
    27   }
    28   return ans;
    29 }
    30 ll getsum2(int x){
    31     ll ans = 0;
    32    while (x >= 1) {
    33      ans = ans + c2[x];
    34      x = x - lowbit(x);
    35   }
    36   return ans;
    37 }
    38 struct node{
    39     ll x,v;
    40     bool operator < (const node &b) const{
    41         return x<b.x ;
    42     }
    43 }p[maxn];
    44 map<ll,int> m;
    45 vector<int> speed;
    46 int main(){
    47     scanf("%d",&n);
    48     for(int i = 1;i<=n;i++){
    49         ll x;scanf("%lld",&x);
    50         p[i].x = x;
    51     }
    52     for(int i = 1;i<=n;i++){
    53         ll v;scanf("%lld",&v);
    54         p[i].v = v;
    55         if(m[v] == 0) m[v] = 1,speed.push_back(v);
    56     }
    57     ll ans = 0;
    58     sort(p+1,p+1+n);
    59     sort(speed.begin(),speed.end());
    60     for(int i = 1;i<=n;i++){
    61         ll cur = p[i].v;
    62         int pos = upper_bound(speed.begin(),speed.end(),cur) - speed.begin();
    63         ll sum = getsum(pos),cnt = getsum2(pos);
    64         ans+=p[i].x*(cnt) - sum;
    65         add(pos,p[i].x),add2(pos,1);
    66     }
    67     cout<<ans;
    68     return 0;
    69 }
    View Code
  • 相关阅读:
    UVALive 6319 暴力
    UVALive 6322 最大匹配
    uvalive 6323 状态压缩DP
    hdu 3874 树状数组
    hdu 3721 树的直径
    hdu 4258 斜率DP
    组队练习 2011年福州全国邀请赛
    FZU 2041 二分枚举
    Kafka基础教程(三):C#使用Kafka消息队列
    Kafka基础教程(二):Kafka安装
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12380369.html
Copyright © 2020-2023  润新知