【线段树】【CDQ分治】回转寿司
来源:互联网 发布:淘宝店主自己做模特 编辑:程序博客网 时间:2024/04/28 22:12
题目大意
给你一个序列,求连续子序列和在【L,R】之间的方案数
N≤100000,|Ai|≤100000,0≤L, R≤109.
分析
这是我打的第一题CDQ(太菜了)
我对这题印象很深刻
当时大家有各种做法
好像都是线段树?
然后这时出现了一股清流
dhr的CDQ分治(orz dhr 好短啊)
然后愉悦的改完后就没管了
很久以后yzx讲CDQ分治时想到我曾经打过一道
先递归再更新答案然后sort回溯
#include<cstdio>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;int n,l,r,a[100050];LL s[100050],ans;void solve(int p,int q){ if(p>=q)return; int mid=(p+q)/2; solve(p,mid); solve(mid+1,q); int u=p,v=p; for(int i=mid+1;i<=q;i++){ while(u<=mid&&s[i]-s[u]>=l)u++; while(v<=mid&&s[i]-s[v]>r)v++; ans+=max(u-v,0); } sort(s+p,s+q+1);}int main(){ scanf("%d%d%d",&n,&l,&r); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); s[i]=a[i]+s[i-1]; } solve(0,n); printf("%lld",ans);}
现在再补上一种值域线段树的做法
对于前缀和s【i】(i表示以i为末尾)
满足
得
将s【i】插入一颗值域线段树(初始化时插入0)
对于每个s【j】查询值域在[s【j】-l,s【j】-r]之间的s【i】个数
#include<cstdio>#define INF 10000000000#define N 100010#define mid ((l+r)>>1)using namespace std;typedef long long LL;LL ans,sum,L,R;int n,u,v,top,p,t[N*40],lc[N*40],rc[N*40],rt;void Ins(int &x,LL l,LL r){ if(!x)x=++top; t[x]++; if(l==r)return; if(sum<=mid)Ins(lc[x],l,mid); else Ins(rc[x],mid+1,r);}int Que(int x,LL l,LL r){ if(!x)return 0; if(L<=l&&r<=R)return t[x]; int ans=0; if(L<=mid)ans+=Que(lc[x],l,mid); if(R>mid)ans+=Que(rc[x],mid+1,r); return ans;}int main(){ freopen("data.txt","r",stdin); scanf("%d%d%d",&n,&u,&v); Ins(rt,-INF,INF); for(int i=1;i<=n;i++){ scanf("%d",&p); sum+=p; L=sum-v,R=sum-u; ans+=Que(rt,-INF,INF); Ins(rt,-INF,INF); } printf("%lld\n",ans);}
还有一种以i为首的树状数组
链接
感觉二分可以换成two pointer
或者可以看Orz 曾老师的代码
#include<cstdio>#include<algorithm>#define ll long longusing namespace std;inline ll rd(){ ll c, r=0, s=1; while((c=getchar())<48||57<c) if(c=='-') s=-1; while(c>47&&58>c) r=10*r+c-48, c=getchar(); return s*r;}#define mxn 100233ll n, l, r, i, j;pair<ll, ll> a[mxn];#define fir(i) a[i].first#define sec(i) a[i].second//第i小的前缀的值与序号 ll b[mxn];inline void add(ll i, ll x) {for(;i<n+2; i+=i&-i) b[i]+=x;}inline ll sum(ll i) {ll r=0; for(;i; i-=i&-i) r+=b[i]; return r;}ll ans;inline ll solve(ll m){ if(m<0) return 0; ans=0; for(i=1; i<n+2; i++) b[i]=0; for(i=j=1; i<n+1; add(sec(++i), -1)) { for(;j<n+1&&fir(j+1)<=fir(i)+m; add(sec(++j), 1)); ans+=j-i-sum(sec(i)); } return ans;}inline void debug(){ for(ll ii=0; ii<=fir(n+1); ii++) printf("%I64d %I64d\n", ii, solve(ii));}int main(){ n=rd(); l=rd(); r=rd(); sec(1)=1; for(i=2; i<=n+1; i++) a[i]=make_pair(fir(i-1)+rd(), i); sort(a+1, a+n+2); printf("%lld\n", solve(r)-solve(l-1)); //debug(); return 0;}
阅读全文
0 0
- 【线段树】【CDQ分治】回转寿司
- [BZOJ4627][BeiJing2016]回转寿司 cdq分治
- bzoj 4627: [BeiJing2016]回转寿司 线段树
- BZOJ 4627回转寿司(值域线段树)
- BZOJ4627 回转寿司(值域线段树)
- BZOJ 4627: [BeiJing2016]回转寿司 cdq
- BZOJ 4627: [BeiJing2016]回转寿司【前缀和,值域线段树
- bzoj 4627 回转寿司(权值线段树)
- bzoj-4627 [BeiJing2016]回转寿司 hash+权值线段树
- HDU6183 cdq分治+线段树
- 回转寿司
- 【BZOJ2773】ispiti【CDQ分治】【线段树】
- COGS 577 蝗灾 线段树+CDQ分治
- BZOJ4627 [BeiJing2016]回转寿司
- 4627: [BeiJing2016]回转寿司
- Bzoj4627: [BeiJing2016]回转寿司
- Bzoj4627:BeiJing2016-回转寿司
- 【BZOJ3295】动态逆序对,CDQ分治/BIT套权值线段树
- 51nod 1270 数组的最大代价 绝对值取极值问题
- A1042. Shuffling Machine(洗牌机)
- ArrayBlockingQueue
- 深度学习的Attention模型
- HDU (1575)Tr A ---矩阵快速幂
- 【线段树】【CDQ分治】回转寿司
- 51nod1013-快速幂&逆元-3的幂的和
- LayoutInflater中inflate方法两个参数和三个参数的区别
- HDU1548-A strange lift
- 使用idea创建一个wordcount例子
- LINUX学习笔记(七)
- 二分图的最大匹配、完美匹配和匈牙利算法
- 爬虫之旅(五)
- [NOIP2017模拟]杆子的排列