zoukankan      html  css  js  c++  java
  • [洛谷P5677][题解][GZOI2017]配对统计

    先上题

    这道题乍一看毫无头绪,其实找到了切入点就很简单了

    我们发现,所有可用的配对是可以预处理出来的!!!(显然)

    于是我们可以排一遍序,统计一个数两边的数,然后把较小的配对记录下来

    注意:如果左右相等需要都记录,必须是两个if,不能顺手打成else if(具体看代码)

    那么询问如何处理呢?

    我们显然不能一个个暴力统计,于是就想到了一个类似莫队的方法:
    按左端点排序,挨个向左加

    然后我们就可以很快看题解想到一个求答案的方法:

    开一个树状数组维护右端点出现的次数(这里的树状数组起到了类似桶的作用)

    由于l是下降的,所以已统计过的r绝对不会飞到l左边导致重复统计

    这时只需要求一下1~r的前缀和即可

    Code:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cmath>
      4 #include<ctime>
      5 #include<cstring>
      6 #include<iostream>
      7 #include<algorithm>
      8 #include<stack>
      9 #include<queue>
     10 #include<vector>
     11 #include<bitset>
     12 #include<set>
     13 #include<map>
     14 #define LL long long
     15 #define rg register
     16 #define us unsigned
     17 #define eps 1e-6
     18 #define INF 0x3f3f3f3f
     19 #define ls k<<1
     20 #define rs k<<1|1
     21 #define tmid ((tr[k].l+tr[k].r)>>1)
     22 #define nmid ((l+r)>>1)
     23 #define Thispoint tr[k].l==tr[k].r
     24 #define pushup tr[k].wei=tr[ls].wei+tr[rs].wei
     25 #define pub push_back
     26 #define lth length
     27 #define int long long
     28 using namespace std;
     29 inline void Read(int &x){
     30     int f=1;
     31     char c=getchar();
     32     x=0;
     33     while(c<'0'||c>'9'){
     34         if(c=='-')f=-1;
     35         c=getchar();
     36     }
     37     while(c>='0'&&c<='9'){
     38         x=(x<<3)+(x<<1)+c-'0';
     39         c=getchar();
     40     }
     41     x*=f;
     42 }
     43 #define N 300010
     44 int n,m,t[N],ans[N],tot;
     45 
     46 struct Num {//原数组存值和位置 
     47     int num,idx; 
     48     bool operator < (const Num a)const{
     49         return num<a.num;
     50     }
     51 }a[N];
     52 
     53 struct Couple {//配对数组存各自位置 
     54     int l,r;
     55     bool operator < (const Couple a)const{
     56         return l<a.l;
     57     }
     58 }c[N];
     59 
     60 struct Question {//询问数组存区间和排名(输出用) 
     61     int l,r,idx;
     62     bool operator < (const Question a)const{
     63         return l<a.l;
     64     }
     65 }q[N];
     66 /*---以下为树状数组基本操作---*/
     67 inline int lbt(int x){
     68     return x&(-x);
     69 }
     70 inline void add(int x,int num){
     71     while(x<=n){
     72         t[x]+=num;
     73         x+=lbt(x);
     74     }
     75 }
     76 inline int query(int x){
     77     int ans=0;
     78     while(x){
     79         ans+=t[x];
     80         x-=lbt(x);
     81     }
     82     return ans;
     83 }
     84 /*---以上为树状数组基本操作---*/
     85 signed main(){
     86     Read(n),Read(m);//第一轮输入原数组,从小到大排序 
     87     for(rg int i=1;i<=n;i++){
     88         Read(a[i].num),a[i].idx=i;
     89     }
     90     sort(a+1,a+1+n);
     91     
     92     a[0].num=a[n+1].num=INF;//第二轮预处理出所有可用配对 
     93     for(rg int i=1;i<=n;i++){
     94         int lft=a[i].num-a[i-1].num,rit=a[i].num-a[i+1].num;
     95         if(abs(lft)<=abs(rit)){//用左边的 
     96             c[++tot].l=min(a[i].idx,a[i-1].idx);
     97             c[tot].r=max(a[i].idx,a[i-1].idx);
     98         }
     99         if(abs(lft)>=abs(rit)){//用右边的(注意此处) 
    100             c[++tot].l=min(a[i].idx,a[i+1].idx);
    101             c[tot].r=max(a[i].idx,a[i+1].idx);
    102         }
    103     }
    104     sort(c+1,c+1+tot);
    105     
    106     for(rg int i=1;i<=m;i++){//第三轮输入询问,排序 
    107         Read(q[i].l),Read(q[i].r),q[i].idx=i;
    108     }
    109     sort(q+1,q+1+m);
    110     
    111     for(rg int i=m;i>=1;i--){//第四轮求答案 
    112         while(q[i].l<=c[tot].l){//往左跑到头 
    113             add(c[tot].r,1);
    114             tot--;
    115         }
    116         ans[q[i].idx]=query(q[i].r);//记录一下答案 
    117     }
    118     int Ans=0;
    119     for(rg int i=1;i<=m;i++){
    120         Ans+=ans[i]*i;
    121     }
    122     cout<<Ans<<endl;
    123     return 0;
    124 }

    完结撒花

    内容来自_ajhfff_的博客(https://www.cnblogs.com/juruoajh/),未经允许,不得转载。
  • 相关阅读:
    漂亮的代码5:数组与字符一样的操作
    漂亮的代码4:缓存器的妙用
    漂亮的代码3:flatten 一个数组
    漂亮的代码2:遍历文件夹目录,使用promise
    漂亮的代码1:计算器
    nodejs 代码设计模式1:同步函数变异步
    [翻译]现代java开发指南 第二部分
    Httpclient远程调用WebService示例
    Java代码使用正则验证和常用工具方法
    简单将集合的内容转为字符串
  • 原文地址:https://www.cnblogs.com/juruoajh/p/12555342.html
Copyright © 2011-2022 走看看