这道题乍一看毫无头绪,其实找到了切入点就很简单了
我们发现,所有可用的配对是可以预处理出来的!!!(显然)
于是我们可以排一遍序,统计一个数两边的数,然后把较小的配对记录下来
注意:如果左右相等需要都记录,必须是两个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 }
完结撒花