HDU 4638 Group(莫队)题解
题意:n个数,每个数有一个值,每次询问一个区间,问你这个区间能分成连续的几段(比如7 1 2 8 就是两端 1 2 和 7 8)
思路:莫队。因为L、R移动顺序wa了20发...问了一下别人,都是先扩大范围,再缩小...以后就这样写吧...
代码:
#include<cmath> #include<cstdio> #include<vector> #include<cstring> #include <iostream> #include<algorithm> using namespace std; const int maxn = 100000 + 10; int vis[maxn], arr[maxn], ans[maxn]; int T, n, m, ret; struct node{ int l, r; int pos, id; bool operator < (const node &x) const{ if(pos == x.pos) return r < x.r; return pos < x.pos; } }p[maxn]; void add(int x){ vis[x] = 1; if(vis[x - 1] && vis[x + 1]) ret--; else if(!vis[x - 1] && !vis[x + 1]) ret++; } void del(int x){ vis[x] = 0; if(vis[x - 1] && vis[x + 1]) ret++; else if(!vis[x - 1] && !vis[x + 1]) ret--; } void solve(){ memset(vis, 0 ,sizeof(vis)); int L = 1, R = 0; ret = 0; for(int i = 0; i < m; i++){ int l = p[i].l, r = p[i].r; if(r < L || l > R){ ret = 0; for(int i = L; i <= R; i++) vis[arr[i]] = 0; for(int i = l; i <= r; i++) add(arr[i]); L = l, R = r; } while(L > l){ L--; add(arr[L]); } while(R < r){ R++; add(arr[R]); } while(L < l){ del(arr[L]); L++; } while(R > r){ del(arr[R]); R--; } ans[p[i].id] = ret; } } int main(){ scanf("%d", &T); while(T--){ scanf("%d%d", &n, &m); int block = sqrt(n * 1.0); for(int i = 1; i <= n; i++) scanf("%d", &arr[i]); for(int i = 0; i < m; i++){ scanf("%d%d", &p[i].l, &p[i].r); p[i].id = i; p[i].pos = p[i].l / block; } sort(p, p + m); solve(); for(int i = 0; i < m; i++){ printf("%d\n", ans[i]); } } return 0; }