【BZOJ4540】【HNOI2016】序列
2018-03-20 19:57
232 查看
【题目链接】
点击打开链接
【思路要点】
询问一个区间内不方便用线段树维护信息,可离线,考虑莫队。
这样的话,我们希望支持快速询问\(f(l,r)=\sum_{i=l}^{r}Min_{j=l}^{i}\{a_i\}\)和\(g(l,r)=\sum_{i=l}^{r}Min_{j=i}^{r}\{a_j\}\)。
用单调栈处理出每个数向左/向右第一个小于它的数,并倍增。询问时在倍增数组上二分,可以得到\(O(N*\sqrt{N}*LogN)\)的总复杂度。
进一步考虑,我们预处理出\(f(i,N)\)、\(g(1,i)\)和一个ST表,支持询问区间最左/右侧的最小值的位置。
令\([l,r]\)最右侧的区间最小值位置为\(pos\),\(pos\)右侧第一个比它大的数在\(suf\)。
则\(f(l,r)=f(pos,N)-f(suf,N)-(suf-r-1)*a_{pos}\),\(g(l,r)\)同理。
时间复杂度\(O(N*\sqrt{N})\)。
【代码】
点击打开链接
【思路要点】
询问一个区间内不方便用线段树维护信息,可离线,考虑莫队。
这样的话,我们希望支持快速询问\(f(l,r)=\sum_{i=l}^{r}Min_{j=l}^{i}\{a_i\}\)和\(g(l,r)=\sum_{i=l}^{r}Min_{j=i}^{r}\{a_j\}\)。
用单调栈处理出每个数向左/向右第一个小于它的数,并倍增。询问时在倍增数组上二分,可以得到\(O(N*\sqrt{N}*LogN)\)的总复杂度。
进一步考虑,我们预处理出\(f(i,N)\)、\(g(1,i)\)和一个ST表,支持询问区间最左/右侧的最小值的位置。
令\([l,r]\)最右侧的区间最小值位置为\(pos\),\(pos\)右侧第一个比它大的数在\(suf\)。
则\(f(l,r)=f(pos,N)-f(suf,N)-(suf-r-1)*a_{pos}\),\(g(l,r)\)同理。
时间复杂度\(O(N*\sqrt{N})\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 100005; const int SIZE = 1500; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct edge {int x, y, a, b; }; struct info {int x, y, a, b, home; }; edge e[MAXN]; info a[MAXN]; int n, m, q; int tot, l[MAXN], r[MAXN], belong[MAXN]; int f[MAXN], Maxa[MAXN], Maxb[MAXN], size[MAXN]; int top, s[MAXN], sf[MAXN], sMaxa[MAXN], sMaxb[MAXN], ssize[MAXN]; bool ans[MAXN], instack[MAXN]; bool cmpea(edge x, edge y) {return x.a < y.a; } bool cmpia(info x, info y) {return x.a < y.a; } bool cmpeb(edge x, edge y) {return x.b < y.b; } bool cmpib(info x, info y) {return x.b < y.b; } int tmpfind(int x) { if (f[x] == x) return x; else return tmpfind(f[x]); } void tmpmerge(int x, int y, int a, int b) { int tx = tmpfind(x), ty = tmpfind(y); if (size[tx] < size[ty]) swap(tx, ty); if (!instack[tx]) { instack[tx] = true; s[++top] = tx; sf[tx] = f[tx]; sMaxa[tx] = Maxa[tx]; sMaxb[tx] = Maxb[tx]; ssize[tx] = size[tx]; } if (!instack[ty]) { instack[ty] = true; s[++top] = ty; sf[ty] = f[ty]; sMaxa[ty] = Maxa[ty]; sMaxb[ty] = Maxb[ty]; ssize[ty] = size[ty]; } f[ty] = tx; chkmax(Maxa[tx], a); chkmax(Maxa[tx], Maxa[ty]); chkmax(Maxb[tx], b); chkmax(Maxb[tx], Maxb[ty]); if (tx == ty) return; size[tx] += size[ty]; } int find(int x) { if (f[x] == x) return x; else return f[x] = find(f[x]); } void merge(int x, int y, int a, int b) { int tx = find(x), ty = find(y); if (size[tx] < size[ty]) swap(tx, ty); f[ty] = tx; chkmax(Maxa[tx], a); chkmax(Maxa[tx], Maxa[ty]); chkmax(Maxb[tx], b); chkmax(Maxb[tx], Maxb[ty]); if (tx == ty) return; size[tx] += size[ty]; } void restore() { while (top) { int tmp = s[top--]; instack[tmp] = false; f[tmp] = sf[tmp]; Maxa[tmp] = sMaxa[tmp]; Maxb[tmp] = sMaxb[tmp]; size[tmp] = ssize[tmp]; } } int main() { read(n), read(m); for (int i = 1; i <= m; i++) read(e[i].x), read(e[i].y), read(e[i].a), read(e[i].b); for (int i = 1; i <= m; i++) { if (i % SIZE == 1 % SIZE) l[++tot] = i; belong[i] = tot; r[tot] = i; } sort(e + 1, e + m + 1, cmpea); read(q); for (int i = 1; i <= q; i++) read(a[i].x), read(a[i].y), read(a[i].a), read(a[i].b), a[i].home = i; sort(a + 1, a + q + 1, cmpia); int last = 0; for (int p = 1; p <= tot; p++) { int end = last, val = e[r[p]].a; if (r[p] != m && e[r[p]].a == e[r[p] + 1].a) val--; while (end < q && a[end + 1].a <= val) end++; if (last == end) continue; sort(e + 1, e + l[p], cmpeb); sort(a + last + 1, a + end + 1, cmpib); for (int i = 1; i <= n; i++) { f[i] = i; Maxa[i] = -1; Maxb[i] = -1; size[i] = 1; } int now = 1; for (int i = last + 1; i <= end; i++) { while (now < l[p] && e[now].b <= a[i].b) { merge(e[now].x, e[now].y, e[now].a, e[now].b); now++; } for (int j = l[p]; j <= r[p]; j++) { if (e[j].a > a[i].a) break; if (e[j].b <= a[i].b) tmpmerge(e[j].x, e[j].y, e[j].a, e[j].b); } int tx = tmpfind(a[i].x), ty = tmpfind(a[i].y); if (tx == ty && Maxa[tx] == a[i].a && Maxb[tx] == a[i].b) ans[a[i].home] = true; restore(); } } for (int i = 1; i <= q; i++) if (ans[i]) printf("Yes\n"); else printf("No\n"); return 0; }
相关文章推荐
- bzoj4540【HNOI2016】序列
- bzoj4540: [Hnoi2016]序列
- BZOJ4540 [Hnoi2016]序列 【莫队 + ST表 + 单调栈】
- 【bzoj4540】【HNOI2016】【序列】【莫队+st表】
- [BZOJ4540][HNOI2016]序列 莫队
- bzoj4540 [Hnoi2016]序列 (莫队+ST表+单调栈)
- 【BZOJ4540】【Hnoi2016】序列 线段树
- BZOJ 4540 [Hnoi2016]序列 | 莫队 详细题解
- [Bzoj4540][Hnoi2016] 序列(莫队 + ST表 + 单调队列)
- 【BZOJ4540】[Hnoi2016]序列 莫队算法+单调栈
- [莫队 单调栈] BZOJ 4540 [Hnoi2016]序列
- [bzoj4540][Hnoi2016]序列 莫队+RMQ
- bzoj4540: [Hnoi2016]序列
- bzoj 4540 HNOI 2016 序列 莫队
- bzoj4540: [Hnoi2016]序列
- BZOj 4540: [Hnoi2016]序列 [莫队 st表 预处理]
- bzoj 4540: [Hnoi2016]序列【单调栈+线段树】
- bzoj 4540: [Hnoi2016]序列
- bzoj 4540: [Hnoi2016]序列 莫队算法+rmq
- bzoj 4540: [Hnoi2016]序列 莫队算法