HDU Group
Group
题目:
给出n个数。是1-n的排列。要求你每次给你一个区间求出这个区间能够被分成的小区间个数。一个不连续的数能够被分成一个小区间。t-1,t或t,t+1表示连续。
算法:
高速做法应该是线段树。可是,我不会。
学了一个块状数组。
#include <iostream> #include <algorithm> #include <vector> #include <cstdio> #include <cmath> #include <cstring> using namespace std; const int MAXN = 100000 + 10; struct Node{ int l,r,id,b; bool operator < (const Node& rhs) const { if(b != rhs.b){ return b < rhs.b; } return r < rhs.r; } }query[MAXN]; int seg[MAXN]; bool vst[MAXN]; int n,m,res; int ans[MAXN]; void cal(int x,int &l,int &r){ int L = query[x].l, R = query[x].r; while(L < l){ //须要将左右区间进行放大,否则可能出现左右游标交错的情况 --l; int t = seg[l]; vst[t] = 1; if(vst[t-1]&&vst[t+1]) --res; else if(!vst[t-1]&&!vst[t+1]) ++res; } while(R > r){ ++r; int t = seg[r]; vst[t] = 1; if(vst[t-1]&&vst[t+1]) --res; else if(!vst[t-1]&&!vst[t+1]) ++res; } while(L > l){ int t = seg[l]; vst[t] = 0; if(vst[t-1]&&vst[t+1]) ++res; else if(!vst[t-1]&&!vst[t+1]) --res; ++l; } while(R < r){ int t = seg[r]; vst[t] = 0; if(vst[t-1]&&vst[t+1]) ++res; else if(!vst[t-1]&&!vst[t+1]) --res; --r; } } void solve(){ memset(vst,0,sizeof(vst)); sort(query,query + m); res = 0; int l = query[0].l, r = query[0].r; for(int i = l;i <= r;++i){ int t = seg[i]; vst[t] = 1; if(vst[t-1] && vst[t+1]) --res; else if(!vst[t-1]&&!vst[t+1]) ++res; } ans[query[0].id] = res; for(int i = 1;i < m;++i){ ans[query[i].id] = (cal(i,l,r),res); } for(int i = 0;i < m;++i){ printf("%d\n",ans[i]); } } int main() { int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i = 1;i <= n;++i){ scanf("%d",&seg[i]); } int B = sqrt(1.0*n); for(int i = 0;i < m;++i){ scanf("%d%d",&query[i].l,&query[i].r); query[i].b = query[i].l / B; query[i].id = i; } solve(); } return 0; }