兩道離線線段樹。
比賽時候沒想到。。。。
掃描數組,i從1到n,線段樹維護從1到i每一個約數(1~50000)的出現的最近位置,線段樹存儲的是約數的最大值
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int N=50050; struct Interval{ int l,r,id; }in[N]; struct Tree{ int l,r,Max; }tree[N<<2]; int n,m; int a[N]; int pre[N]; int ans[N]; vector<int> factor[N]; void init(){ for(int i=1;i<N;i++) for(int j=i;j<N;j+=i) factor[j].push_back(i); } bool cmp(struct Interval a,struct Interval b){ return a.r<b.r; } void build(int l,int r,int id){ tree[id].l=l; tree[id].r=r; tree[id].Max=0; if(l!=r){ int mid=(l+r)>>1; build(l,mid,id<<1); build(mid+1,r,id<<1|1); } } void update(int pos,int val,int id){ tree[id].Max=max(tree[id].Max,val); if(tree[id].l==tree[id].r) return ; int mid=(tree[id].l+tree[id].r)>>1; if(mid>=pos) update(pos,val,id<<1); else update(pos,val,id<<1|1); } int query(int l,int r,int id){ if(tree[id].l==l && tree[id].r==r) return tree[id].Max; int mid=(tree[id].l+tree[id].r)>>1; if(mid>=r) return query(l,r,id<<1); else if(mid<l) return query(l,r,id<<1|1); else return max(query(l,mid,id<<1),query(mid+1,r,id<<1|1)); } int main(){ init(); int t,T; int i,j,k; scanf("%d",&T); for(t=1;t<=T;t++){ scanf("%d",&n); build(1,n,1); for(i=1;i<=n;i++){ scanf("%d",&a[i]); } scanf("%d",&m); for(i=0;i<m;i++){ scanf("%d %d",&in[i].l,&in[i].r); in[i].id=i; } sort(in,in+m,cmp); memset(pre,0,sizeof(pre)); for(i=1,j=0;i<=n && j<m;i++){ for(k=0;k<factor[a[i]].size();k++){ int tem=factor[a[i]][k]; if(pre[tem]!=0){ update(pre[tem],tem,1); } pre[tem]=i; } while(j<m && in[j].r==i){ ans[in[j].id]=query(in[j].l,in[j].r,1); j++; } } for(i=0;i<m;i++) printf("%d\n",ans[i]); } return 0; }
BOJ的那題找不到了,做完這道題之後,發現這兩題很像,都是離線線段樹做法。(這道題還是隊友出的,膜拜)
先為數組中每個點i一個最小區間l,r滿足a[i]>a[l] && a[i]<a[r],l<i<r
然後i從1開始掃描,每次把能加入的點加入,然後處理右端點為i的查詢
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> using namespace std; const int MAXN = 100000+5; const int INF = 0x3f3f3f3f; int T, N, Q, a[MAXN], s[MAXN], t[MAXN]; int idq[MAXN], q[MAXN], cnt[MAXN], p[MAXN]; int x[MAXN], y[MAXN], ida[MAXN]; int Tr[MAXN<<2], mark[MAXN<<2]; void Build(int idx, int L, int R) { Tr[idx] = mark[idx] = 0; if (L == R) return; int left = idx<<1, right = idx<<1|1, mid = (L+R)>>1; Build(left, L, mid); Build(right, mid+1, R); } void PushDown(int idx) { int left = idx<<1, right = idx<<1|1, &mk = mark[idx]; Tr[left] += mk; mark[left] += mk; Tr[right] += mk; mark[right] += mk; mk = 0; } void Update(int idx, int L, int R, int l, int r, int c) { if (l <= L && R <= r) { Tr[idx] += c; mark[idx] += c; return; } if (mark[idx]) PushDown(idx); int left = idx<<1, right = idx<<1|1, mid = (L+R)>>1; if (l <= mid) Update(left, L, mid, l, r, c); if (mid < r) Update(right, mid+1, R, l, r, c); } int Query(int idx, int L, int R, int x) { if (x == L && R == x) return Tr[idx]; if (mark[idx]) PushDown(idx); int left = idx<<1, right = idx<<1|1, mid = (L+R)>>1; if (x <= mid) return Query(left, L, mid, x); else return Query(right, mid+1, R, x); } bool cmpq(const int &a, const int &b) { return t[a] < t[b]; } bool cmpa(const int &a, const int &b) { return y[a] < y[b]; } int main() { //freopen("data.in", "r", stdin); //freopen("data.out", "w", stdout); scanf("%d", &T); for (int cas = 1; cas <= T; cas++) { printf("Case %d:\n", cas); scanf("%d", &N); stack<int> stal, star; a[0] = 0; stal.push(0); for (int i = 1; i <= N; i++) { scanf("%d", &a[i]); while (a[i] <= a[stal.top()]) stal.pop(); x[i] = stal.top(); stal.push(i); } a[N+1] = INF; star.push(N+1); for (int i = N; i >= 1; i--) { while (a[i] >= a[star.top()]) star.pop(); y[i] = star.top(); star.push(i); ida[i] = i; } sort(ida+1, ida+1+N, cmpa); scanf("%d", &Q); for (int i = 1; i <= Q; i++) { scanf("%d%d", &s[i], &t[i]); if (s[i] > t[i]) swap(s[i], t[i]); idq[i] = i; q[i] = 0; } sort(idq+1, idq+1+Q, cmpq); Build(1, 1, N); for (int i = 1, j = 1, k = 1; i <= N; i++) { for (; y[ida[k]] == i && k <= N; k++) if (x[ida[k]]) Update(1, 1, N, 1, x[ida[k]], 1); for (; t[idq[j]] == i && j <= Q; j++) q[idq[j]] = Query(1, 1, N, s[idq[j]]); } for (int i = 1; i <= Q; i++) printf("%d\n", q[i]); } return 0; }