Codeforces Beta Round #75 (Div. 1 Only) B. Queue 线段树。单点更新
http://codeforces.com/problemset/problem/91/B
题意:
给你n个数,求得i 到n中小于a[i]的最右边的a[j],然后求a[i]到a[j]之间包含了多少个数。
思路:
首先自己在做这道题的时候没有认真读题,直接把题意搞成求得i 到n中小于a[i]的最右边的a[j],然后求a[i]到a[j]之间包含了多少个小于a[i]的数了。。。结果样例都没过。唉自己还是太粗心,一定要认真把题意搞清楚,然后把想法想好了再敲。不过也算是做了另一道题目吧。
首先我的思路,好像比较复杂。 我们利用线段树维护小于a[i]的区间[1,a[i]]的最大坐标值,当然要将数列离散话,因为a[i]最大为10^9 而n最大是10^5 .每次插入数据更新区间最值,然后就是求出该区间最值与当前坐标比较求个数。
View Code
By E_star, contest: Codeforces Beta Round #75 (Div. 1 Only), problem: (B) Queue, Accepted, # #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 1073741824 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 1000007 #define N 1000007 using namespace std; //freopen("data.in","r",stdin); struct node{ int val; int pos; }a[N]; int X[N]; int val[N*4]; int pos[N]; void pushup(int rt){ val[rt] = max(val[rt<<1],val[rt<<1|1]); } void update(int pos,int sc,int l,int r,int rt){ if (l == r){ val[rt] = sc; return ; } int m = (l + r)>>1; if (pos <= m) update(pos,sc,lc); else update(pos,sc,rc); pushup(rt); } int query(int L,int R,int l,int r,int rt){ if (l >= L && r <= R){ return val[rt]; } int res = 0; int m = (l + r)>>1; if (L <= m) res = max(res,query(L,R,lc)); if (R > m) res = max(res,query(L,R,rc)); return res; } int bSearch(int p,int L,int R){ int l = L; int r = R; int ans = 0; while (l <= r){ int m = (l + r)>>1; if (X[m] <= p){ l = m + 1; ans = m; } else{ r = m - 1; } //puts("<<<<"); } return ans; } int main(){ //freopen("data.in","r",stdin); int i; int n; while (~scanf("%d",&n)){ for (i = 1; i <= n; ++i){ scanf("%d",&a[i].val); a[i].pos = i; X[i] = a[i].val; } //离散化 sort(X + 1,X + 1 + n); int k = 1; for (i = 2; i <= n; ++i){ if (X[i] != X[i - 1]) X[++k] = X[i]; } //每插进一个点就更新[1,a[i]]区间最值 CL(val,0); for (i = 1; i <= n; ++i){ pos[i] = bSearch(a[i].val,1,k); update(pos[i],a[i].pos,1,k,1); } for (i = 1; i < n; ++i){ int p = bSearch(a[i].val - 1,1,k);//二分查找第一个小于a[i]的值 if (p == 0){ printf("-1 "); continue; } int ans = query(1,p,1,k,1);//询问该区间的最大坐标 if (ans <= a[i].pos) printf("-1 "); else{ ans = ans - a[i].pos - 1; printf("%d ",ans); } } printf("-1\n"); } return 0; }
别人的思路,思考方向不一样,做法就不一样。我觉得这个想法很简洁明了。他直接记录区间最值,枚举每个a[i]每次把枚举到的a[i]更新成inf,线段树求出整个区间最小值,与该值比较,如果大于等于它肯定输出-1,否则线段树里求右边第一个小于a[i]的值的坐标。 (这里最巧妙数的求最右边第一个小于a[i]的坐标,以前没接触过这个求法)
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <set> #include <map> #include <string> #define CL(a,num) memset((a),(num),sizeof(a)) #define iabs(x) ((x) > 0 ? (x) : -(x)) #define Min(a,b) (a) > (b)? (b):(a) #define Max(a,b) (a) > (b)? (a):(b) #define ll long long #define inf 0x7f7f7f7f #define MOD 1073741824 #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define test puts("<------------------->") #define maxn 100007 #define M 1000007 #define N 1000007 using namespace std; //freopen("data.in","r",stdin); int a[N],val[N]; void pushup(int rt){ val[rt] = min(val[rt<<1],val[rt<<1|1]); } void build(int l,int r,int rt){ if (l == r){ scanf("%d",&val[rt]); a[l] = val[rt]; return ; } int m = (l + r)>>1; build(lc); build(rc); pushup(rt); } void update(int pos,int l,int r,int rt){ if (l == r){ val[rt] = inf; return ; } int m = (l + r)>>1; if (pos <= m) update(pos,lc); else update(pos,rc); pushup(rt); } int query(int sc,int l,int r,int rt){ if (l == r) return l; int m = (l + r)>>1; if (val[rt<<1|1] < sc) return query(sc,rc); else return query(sc,lc); } int main(){ //freopen("data.in","r",stdin); int i; int n; while (~scanf("%d",&n)){ build(1,n,1); for (i = 1; i <= n; ++i){ update(i,1,n,1); if (val[1] >= a[i]){ printf("-1%c",i == n ? '\n' : ' '); } else{ int pos = query(a[i],1,n,1); printf("%d%c",pos - i - 1,i == n ? '\n' : ' '); } } } return 0; }