您的位置:首页 > 其它

【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})\)。
【代码】
#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: