标签:
你正在和小冰玩一个猜数字的游戏。小冰首先生成一个长为N的整数序列A1, A2, …, AN。在每一轮游戏中,小冰会给出一个区间范围[L, R],然后你要猜一个数K。如果K在AL, AL+1, …, AR中,那么你获胜。
在尝试了几轮之后,你发现这个游戏太难(无聊)了。小冰决定给你一些提示,你每猜一次,小冰会告诉你K与AL, AL+1, …, AR中最接近的数的绝对差值,即min(|Ai - K|), L ≤ i ≤ R。
现在,请你实现这个新功能。
第一行为一个整数T,表示数据组数。
每组数据的第一行为两个整数N和Q。
第二行为N个由空格分开的整数,分别代表A1, A2, …, AN。
接下来Q行,每行三个由空格隔开的整数L、R、K。
每组数据的先输出一行"Case #X:",X为测试数据编号。
接下来对每个询问输出一行,每行为一个整数,即为所求的值。
1 ≤ T ≤ 20
0 ≤ Ai, K ≤ 109
1 ≤ L ≤ R ≤ N
小数据
1 ≤ N, Q ≤ 1000
大数据
1 ≤ N, Q ≤ 200000
输入数据量较大,推荐使用scanf / BufferedReader等IO方法。
1 9 3 1 8 3 4 9 2 7 6 5 1 9 10 3 7 9 5 6 5
Case #1: 1 0 3
把a[i],和询问k离线,从小到大排序,保证询问k时只插入≤k的
同理>k
注意set操作可能为-INF,_min不能初始化为-1,而要为-INF
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<cctype> #include<ctime> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Fork(i,k,n) for(int i=k;i<=n;i++) #define Rep(i,n) for(int i=0;i<n;i++) #define ForD(i,n) for(int i=n;i;i--) #define RepD(i,n) for(int i=n;i>=0;i--) #define Lson (o<<1) #define Rson ((o<<1)+1) #define MEM(a) memset(a,0,sizeof(a)); #define MEM2(a,i) memset(a,i,sizeof(a)); #define MEMI(a) memset(a,127,sizeof(a)); #define MEMi(a) memset(a,128,sizeof(a)); #define INF (2139062143) #define F (100000007) #define MAXN (200000+10) #define MAXQ (200000+10) typedef long long ll; int n,q; ll a[MAXN]; class SegmentTree { ll a[MAXN*4],minv[MAXN*4],sumv[MAXN*4],maxv[MAXN*4],addv[MAXN*4],setv[MAXN*4]; int n; public: SegmentTree(){MEM(a) MEM(minv) MEM(sumv) MEM(maxv) MEM(addv) MEM2(setv,-1) } SegmentTree(int _n):n(_n){MEM(a) MEM(minv) MEM(sumv) MEM(maxv) MEM(addv) MEM2(setv,-1) } void mem(int _n) { n=_n; MEM(a) MEM(minv) MEM(sumv) MEM(maxv) MEM(addv) MEM2(setv,-1) } void maintain(int o,int L,int R) { sumv[o]=maxv[o]=minv[o]=0; if (L<R) //只考虑左右子树 { sumv[o]=sumv[Lson]+sumv[Rson]; minv[o]=min(minv[Lson],minv[Rson]); maxv[o]=max(maxv[Lson],maxv[Rson]); } //只考虑add操作 if (setv[o]!=-1) sumv[o]=setv[o]*(R-L+1),minv[o]=maxv[o]=setv[o]; minv[o]+=addv[o];maxv[o]+=addv[o];sumv[o]+=addv[o]*(R-L+1); } int y1,y2,v; void update(int o,int L,int R) //y1,y2,v { if (y1<=L&&R<=y2) { addv[o]+=v; } else{ pushdown(o); int M=(R+L)>>1; if (y1<=M) update(Lson,L,M); else maintain(Lson,L,M); if (M< y2) update(Rson,M+1,R); else maintain(Rson,M+1,R); } maintain(o,L,R); } void update2(int o,int L,int R) { if (y1<=L&&R<=y2) { setv[o]=v;addv[o]=0; } else{ pushdown(o); int M=(R+L)>>1; if (y1<=M) update2(Lson,L,M); else maintain(Lson,L,M); //维护pushodown,再次maintain if (M< y2) update2(Rson,M+1,R); else maintain(Rson,M+1,R); } maintain(o,L,R); } void pushdown(int o) { if (setv[o]!=-1) { setv[Lson]=setv[Rson]=setv[o]; addv[Lson]=addv[Rson]=0; setv[o]=-1; } if (addv[o]) { addv[Lson]+=addv[o]; addv[Rson]+=addv[o]; addv[o]=0; } } ll _min,_max,_sum; void query2(int o,int L,int R,ll add) { if (setv[o]!=-1) { _sum+=(setv[o]+addv[o]+add)*(min(R,y2)-max(L,y1)+1); _min=min(_min,setv[o]+addv[o]+add); _max=max(_max,setv[o]+addv[o]+add); } else if (y1<=L&&R<=y2) { _sum+=sumv[o]+add*(R-L+1); _min=min(_min,minv[o]+add); _max=max(_max,maxv[o]+add); } else { // pushdown(o); int M=(L+R)>>1; if (y1<=M) query2(Lson,L,M,add+addv[o]);// else maintain(Lson,L,M); if (M< y2) query2(Rson,M+1,R,add+addv[o]);// else maintain(Rson,M+1,R); } //maintain(o,L,R); } void add(int l,int r,ll v) { y1=l,y2=r;this->v=v; update(1,1,n); } void set(int l,int r,ll v) { y1=l,y2=r;this->v=v; update2(1,1,n); } ll ask(int l,int r,int b=0) { _sum=0,_min=INF,_max=-INF; y1=l,y2=r; query2(1,1,n,0); // cout<<_sum<<' '<<_max<<' '<<_min<<endl; switch(b) { case 1:return _sum; case 2:return _min; case 3:return _max; default:break; } } void print() { For(i,n) cout<<ask(i,i,1)<<' '; cout<<endl; } //先set后add }S; struct ask { ask(int _l=0,int _r=0,ll _k=0,int _i=0){l=_l,r=_r,k=_k;i=_i;} int l,r,i; ll k; friend bool operator<(ask a,ask b){return (a.k<b.k)||(a.k==b.k&&a.l<b.l); } }comm[MAXN+MAXQ]; ll ans1[MAXQ],ans2[MAXQ],qur[MAXQ]; int main() { // freopen("B.in","r",stdin); // freopen(".out","w",stdout); int T; scanf("%d",&T); For(kcase,T) { cin>>n>>q; For(i,n) scanf("%lld",&a[i]); For(i,n) { comm[i]=ask(0,0,a[i]); comm[i].i=i; } printf("Case #%d:\n",kcase); For(i,q) { scanf("%d%d%lld",&comm[n+i].l,&comm[n+i].r,&comm[n+i].k); qur[i]=comm[n+i].k; comm[n+i].i=i; } int m=n+q; sort(comm+1,comm+1+m); S.mem(n); S.set(1,n,-INF); For(i,m) { if (!comm[i].l) S.set(comm[i].i,comm[i].i,comm[i].k); else { ans1[comm[i].i]=S.ask(comm[i].l,comm[i].r,3); } } S.mem(n); S.set(1,n,INF); ForD(i,m) { if (!comm[i].l) S.set(comm[i].i,comm[i].i,comm[i].k); else { ans2[comm[i].i]=S.ask(comm[i].l,comm[i].r,2); } } ll ans=0; For(i,q) printf("%lld\n",min(abs(ans1[i]-qur[i]),abs(ans2[i]-qur[i]))); } return 0; }
hiho 1169(猜数字-线段树求min(|Ai-k|))
标签:
原文地址:http://blog.csdn.net/nike0good/article/details/45822941