zoukankan      html  css  js  c++  java
  • GZOI 2017配对统计 树状数组

    题目

    https://www.luogu.com.cn/problem/P5677

    分析

      最开始读题的时候没有读的太懂,以为i是在选定区间内给的,实际上不是,这道题的意思应该是在l和r的区间内找出有多少个好的配对,这里好的配对是对于整个区间来说的,既然是对于整个区间,我们就不难想到找出好的配对的方法,所以我们可以先找出所有好的配对,然后用树状数组维护个数。

      如何找出好的配对呢?我们先来分析什么叫好的配对,选定的两点间距离比其中一点到除对方外任意一点的距离都小,也就是说这两点差的绝对值最小,这样的话,这两个点在sort排序后一定相邻,这个很好推出,于是我们只要考虑这个点的另一个配对是左边的点还是右边的点,写一个判断就行了,注意特判1和n。

      找出好的配对来,就又向答案接近了一步,现在我们只要进行更新就行了,这里的更新我们枚举左端点,上一步我们已经求出了好的配对(l,r)如果查询的左端点在l的左边,那么从r开始向右就一定至少存在一个好的配对,所以让树状数组中的r对应的位置更新就行。注意我们要倒序枚举左端点,因为我们加入r后所产生的配对只能是在询问区间包含l的情况下才有效。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<vector>
     5 using namespace std;
     6 const int N=3e5+10;
     7 #define ll long long
     8 struct Node{
     9     ll val,id;
    10     bool operator < (const Node&A)const{
    11         return val<A.val;
    12     }
    13 }a[N];
    14 vector<int> point[N],p1[N],p2[N];
    15 ll lowbit(ll x){
    16     return x&-x;
    17 }
    18 void Ins(ll x,ll y){
    19     point[min(x,y)].push_back(max(x,y));//min表示左端点,max表示右端点
    20 }
    21 ll m,n,c[N];
    22 void Add(ll x){
    23     while(x<=n){
    24         c[x]++;
    25         x+=lowbit(x);
    26     }
    27 }
    28 ll query(ll x){
    29     ll ans=0;
    30     while(x){
    31         ans+=c[x];
    32         x-=lowbit(x);
    33     }
    34     return ans;
    35 }
    36 ll ans[N];
    37 int main(){
    38     scanf("%lld%lld",&n,&m);
    39     for(int i=1;i<=n;i++){
    40         scanf("%lld",&a[i].val);a[i].id=i;
    41     }
    42     sort(a+1,a+n+1);
    43     for(int i=1;i<=n;i++){
    44         int Min=0x3f3f3f3f;
    45         if(i!=1&&a[i].val-a[i-1].val<Min){
    46             Min=a[i].val-a[i-1].val;
    47         }
    48         if(i!=n&&a[i+1].val-a[i].val<Min){
    49             Min=a[i+1].val-a[i].val;
    50         }
    51         if(i!=1&&a[i].val-a[i-1].val==Min)Ins(a[i].id,a[i-1].id);
    52         if(i!=n&&a[i+1].val-a[i].val==Min)Ins(a[i+1].id,a[i].id);//取两个端点最小值
    53     }
    54     for(int i=1;i<=m;i++){
    55         int l,r;
    56         scanf("%d%d",&l,&r);
    57         p1[l].push_back(r);
    58         p2[l].push_back(i);//记录坐标位置
    59     }
    60     for(int i=n;i>=1;i--){
    61         for(int j=0;j<(int)point[i].size();j++)Add(point[i][j]);//倒序查询
    62         for(int j=0;j<(int)p1[i].size();j++)ans[p2[i][j]]=query(p1[i][j]);
    63     }
    64     ll sum=0;
    65     for(int i=1;i<=m;i++)
    66         sum+=ans[i]*i;
    67     printf("%lld
    ",sum);
    68 }
  • 相关阅读:
    推荐一些socket工具,TCP、UDP调试、抓包工具
    IE DIV背景透明,点击事件不响应解决方案
    亚马逊的高管和员工们经常阅读的书目
    今日技术文摘 (2013
    Discuz! X3安装第三方主题出现:对不起,您安装的不是正版应用..的解决方法
    chrome浏览器直接编辑源码功能的开通办法
    书单
    editplus教程
    如何让windows更高效?
    conEmu的使用笔记
  • 原文地址:https://www.cnblogs.com/anyixing-fly/p/12461717.html
Copyright © 2011-2022 走看看