代码
转载自https://www.cnblogs.com/cj-xxz/p/9811806.html
写得太好了,可惜没有注释,所以这里解释一下CDQ分治的写法。
首先处理前缀和,要求的是sum[j]-sum[i]<t的区间数量。
离线操作,对前缀和排序,就变成了一个二维偏序问题,
对左区间任意i,右区间取j,答案加上满足偏序关系的对数,类似求逆序对。
处理后效性:将计算完的区间排序成一个非降序的区间,可以消除对后续操作的影响。
#include<bits/stdc++.h> #define int long long const int maxn=2e5+7; inline void read(int &data){ //快读优化 int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} data=x*f; } int n,t,x,sum[maxn],ans; void div(int *beg,int *end){ if(end-beg<=1) return; //如果是单个点 int *mid=beg+(end-beg>>1); //区间中点 div(beg,mid); //分治 div(mid,end); for(int *i=beg,*j=mid;i!=mid;i++,ans+=j-mid){ //答案加上偏序对数 while(j!=end&&(*j)<t+(*i)) ++j;//j往右移动 } std::inplace_merge(beg,mid,end); //归并排序合并成一个非降序的区间 } signed main(){ read(n);read(t); for(int i=1;i<=n;i++){ read(x); sum[i]=sum[i-1]+x; //处理前缀和 } div(sum,sum+1+n); //cdq分治 printf("%lld\n",ans); return 0; }