CF 6E 线段树 or Multiset or 双端队列维护区间最值
2016-08-16 20:53
423 查看
给你一个序列,让你求一个区间中最大值和最小值相差不过k的最长连续序列的长度
线段树版本:
Multiset版本
双端队列版本:(待续)
线段树版本:
#include <stdio.h> #include <string.h> #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 inline int MAX(int a,int b) {return a>b?a:b;} inline int MIN(int a,int b) {return a>b?b:a;} const int N=100005; int ql ,qr ; int Max[N<<2]; int Min[N<<2]; //int sum[N<<2]; void push(int rt) { Max[rt]=MAX(Max[rt<<1] ,Max[rt<<1|1]); Min[rt]=MIN(Min[rt<<1] ,Min[rt<<1|1]); // sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r) { scanf("%d",&Max[rt]); Min[rt]=Max[rt]; return; } int m=(l+r)>>1; build(ls); build(rs); push(rt); } int query(int L,int R,int l,int r,int rt)//区间最大值 { if(L<=l&&r<=R) return Max[rt]; int m=(l+r)>>1; int ret=0; if(L<=m) ret=MAX(ret,query(L,R,ls)); if(R>m) ret=MAX(ret,query(L,R,rs)); return ret; } int query1(int L,int R,int l,int r,int rt)//区间最小值 { if (L<=l&&r<=R) return Min[rt]; int m=(l+r)>>1; int ret=0x3f3f3f3f; if(L<=m) ret=MIN(ret,query1(L,R,ls)); if(R>m) ret=MIN(ret,query1(L,R,rs)); return ret; } //int query2(int L,int R,int l,int r,int rt)//区间最小值 //{ // if (L<=l&&r<=R) // { // return sum[rt]; // } // int m=(l+r)>>1; // int ret=0; // if (L<=m) // ret+=query(L,R,ls); // if (R>m) // ret+=query(L,R,rs); // return ret; //} int main() { int n,k; scanf("%d%d",&n,&k); build(1,n,1); int i,j,ans,t; ans=t=0; for(i=j=1;j<=n;i++) { if(j<i) j=i; while(j<=n&&(query(i,j,1,n,1)-query1(i,j,1,n,1)<=k)) ++j; if(j-i>ans) ans=j-i,ql[0]=i,qr[0]=j-1,t=1; else if(j-i==ans) ql[t]=i,qr[t++]=j-1; } printf("%d %d\n",ans,t); for(i=0;i<t;i++) printf("%d %d\n",ql[i],qr[i]); }
Multiset版本
#include<cstdio> #include<set> int a[100100],c[100100]; using namespace std; multiset<int> s; int main() { int n,k;scanf("%d%d",&n,&k);int l=0,ma=0,t=0; for(int i=0;i<n;i++) { scanf("%d",&a[i]); s.insert(a[i]); while(*s.rbegin()-*s.begin()>k) s.erase(s.find(a[l++]));//注意这里不能是s.erase(a[l++]);这样会删除全部a[l++]这个元素 if(i-l+1>ma){ma=i-l+1;t=0;c[t++]=l;} else if(i-l+1==ma) c[t++]=l; } printf("%d %d\n",ma,t); for(int i=0;i<t;i++) printf("%d %d\n",c[i]+1,c[i]+ma); }
双端队列版本:(待续)
相关文章推荐
- 2017多校第二场 HDU 6047 Maximum Sequence 线段树或者multiset维护区间最值
- Leetcode|Sliding Window Maximum(multiset,优先队列,双端队列和区间树的应用)
- Sliding Window(单调队列维护或线段树求区间最大最小值)
- HDU 5726 GCD (rmq+二分 or 线段树 维护区间gcd)
- POJ 2182 Lost Cows 题解 (线段树维护区间变化or暴力)
- ICPC2017网络赛(北京)Minimum(线段树or树状数组区间最值维护)
- CF 671D Roads in Yusland 线段树维护代价合并的思想 ★ ★ ★ ★
- POJ 3468 A Simple Problem with Integers 线段树维护动态区间和
- 2823 Sliding Window 求区间最值 线段树好慢,能用单调队列
- 平衡二叉树SBT||线段树区间维护poj2892
- NYOJ备用2344 盖伦的告白(线段树||双端队列)
- LuoguP2846[USACO08NOV]光开关Light Switching【线段树维护区间异或】By cellur925
- 线段树维护区间最大值hdu1754
- poj2828 买票 线段树维护连续的区间
- POJ3468(线段树区间维护)
- poj1442--Black Box--优先队列维护堆&&multiset维护堆
- HDU 6070 Dirt Ratio 分数规划 二分 线段树维护区间最值
- 【NOIP2012】 CODE[VS] 1217 借教室(线段树维护区间最小值)
- hdu 1540 Tunnel Warfare (线段树维护左右最长连续区间)
- bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和