• Codeforces Round #624 (Div. 3) F. Moving Points 题解


    第一次写博客 ,请多指教!

    翻了翻前面的题解发现都是用树状数组来做,这里更新一个 线段树+离散化的做法:

    其实这道题是没有必要用线段树的,树状数组就能够解决。但是个人感觉把线段树用熟了会比树状数组更有优势一点

    不多废话 

    http://codeforces.com/contest/1311/problem/F 题目链接

    题意是 给你一堆点的位置和他们运动的速度(可正可负),然后时间无限往后推的情况下问你他们之间所有点的最小距离之和。(不明白自行读题)

    n的范围是2,200000; 显然单纯的一个一个看是不行的,那么自然想到用树状数组或者线段树来做。

    接着可以想到

    1.当两个点的位置xi ,xj满足 xi<xj 并且两个点的速度满足vi <=vj时 他们之间的最短距离一定是当前距离即xj与xi之差。

    2.其余情况最短距离均为零(这一点很容易想)

    那么就好办了 

    思路就是

    1.先对每个点对按照位置从小到大进行排序

    2.按照位置从前到后遍历这些点,进行建树。由当前点的速度确定在数组中的位置。

    3.建树时每更新一个点之前可以求出这个点对答案的贡献 即:

    ans+=(数组中位于当前点前面的点的数量(速度小于当前点速度的点的数量)×当前点的位置)- 前面所有点的位置值的和。

    代码中的公式为 ans+=s[i].x*querye(1,x,1,n,1)-query(1,x,1,n,1);

    由于是按照位置从前到后的顺序上树的,所以不必担心出现比当前点位置靠后的点;

    而关于 统计速度小于当前点速度的点的数量 维护了一个he数组 查询用querye函数,而前面所有点的位置值的和则是最一般的线段树查询。

    至于速度给的数据范围有点大,可以使用离散化将他们集中起来,以便作为下标进行更新。

    上代码 (代码虽然看起来不是很简短但是基本都是模块化操作,耐心看下来就会感觉很容易理解)

    https://www.cnblogs.com/LH2000/category/1656597.html  这里有一些本人写的相关模板函数,可以用作参考。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define lson l,m,rt<<1
     4 #define rson m+1,r,rt<<1|1
     5 #define rush! ios::sync_with_stdio(false);cin.tie(0);
     6 const int inf = 0x3f3f3f3f;
     7 const long long linf = 0x3f3f3f3f3f3f3f3f;
     8 const int maxn=200005;
     9 long long tree[maxn<<2];  //线段树 
    10 long long lsh[200005];   //离散化 数组 
    11 long long he[maxn<<2];
    12 struct trees{
    13     long long x, v;
    14 }s[200005];
    15 bool cmp(const trees &x,const trees &y)
    16 {
    17     return x.x<y.x;
    18 }
    19 void pushup(int rt)
    20 {
    21     tree[rt]=tree[rt<<1]+tree[rt<<1|1];    //用子节点更新父节点的位置值 
    22     he[rt]=he[rt<<1]+he[rt<<1|1];      //用子节点更新父节点数量值 
    23 }
    24 
    25 void update(long long p,long long add,int l,int r,int rt)  //上树  
    26 {
    27     if(l==r)
    28     {
    29         tree[rt]+=add;//更新位置值 
    30         he[rt]++;//更新数量值 
    31         return;
    32     }
    33     int m=(l+r>>1);
    34     if(p<=m) update(p,add,lson);
    35     else update(p,add,rson);
    36     pushup(rt);
    37 }
    38 
    39 long long query(int L,int R,int l,int r,int rt) //查询速度小于当前点速度的元素位置值的和 
    40 {
    41     if(L<=l&&r<=R)
    42     {
    43         return tree[rt];
    44     }
    45     int m=(l+r)>>1;
    46     long long ret=0;
    47     if(L<=m) ret+=query(L,R,lson);
    48     if(R>m) ret+=query(L,R,rson);
    49     return ret;
    50 }
    51 long long querye(int L,int R,int l,int r,int rt) //查询速度小于当前点速度的元素数量 
    52 {
    53     if(L<=l&&r<=R)
    54     {
    55         return he[rt];
    56     }
    57     int m=(l+r)>>1;
    58     long long ret=0;
    59     if(L<=m) ret+=querye(L,R,lson);
    60     if(R>m) ret+=querye(L,R,rson);
    61     return ret;
    62 }
    63 
    64 int main()
    65 {
    66         rush! //加速流 
    67         int n;
    68         cin>>n;
    69         for(int i=1;i<=n;i++)
    70         {
    71             cin>>s[i].x;
    72         }
    73         for(int i=1;i<=n;i++){
    74             cin>>s[i].v;
    75             lsh[i]=s[i].v;
    76         }
    77         sort(lsh+1,lsh+n+1);     //离散化排序 
    78         sort(s+1,s+n+1,cmp);
    79         int cnt=unique(lsh+1,lsh+n+1)-lsh-1;   //离散化数数 
    80         long long ans=0;
    81         for(int i=1;i<=n;i++)
    82         {
    83             long long x=lower_bound(lsh+1,lsh+cnt+1,s[i].v)-lsh;   //离散化 
    84             ans+=s[i].x*querye(1,x,1,n,1)-query(1,x,1,n,1);
    85             update(x,s[i].x,1,n,1);  //上树 
    86         }
    87         cout<<ans<<endl;
    88 }
    rush!
  • 相关阅读:
    Unzip 解压报错
    Linux ftp安装
    关于vsftp出现Restarting vsftpd (via systemctl): Job for vsftpd.service failed because the control 的解决办法
    ASP.NET开发知识总结
    移动端开发调试方法总结
    移动H5优化指南
    基于windows下,node.js之npm
    微服务理解
    SQL Server 触发器
    jQuery验证控件jquery.validate.js使用说明+中文API
  • 原文地址:https://www.cnblogs.com/LH2000/p/12374207.html
Copyright © 2020-2023  润新知