题目大意:
给出一个有n个互不相同元素,有m个询问,每次给出l,r,
询问∑ri=l[a[i]>max(al..i−1)]or[a[i]>max(ai+1..r)]。
1<=n<=10^6
题解:
建一棵笛卡儿树,根的a是最大的。
根据笛卡儿树的性质可得:
1.区间[l..r]里的点一定在l到r的最短路上。
2.对于l到lca的路径上的点,如果是它父亲节点的左节点,对答案贡献1。r的刚好相反。
于是只需要打个能维护lca的算法即可。
tajan可以做到:O(n α(n))
log算法也可以过。
比赛时yy了一个和笛卡儿树很像的搜索森林,加上二分是log的,算法需要离线,在这里放出来标:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
void read(int &x)
{
int sig=1;
char c;
for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1;
x = 0;
for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48;
x *= sig;
}
void write(int x)
{
if (!x) putchar('0');else
{
char s[10];
int i,j=0;
for (;x>0;x/=10) s[j++]=x%10;
for (i=j-1;i>=0;i--) putchar(s[i]+48);
}
putchar('\n');
}
const int N = 1000005;
int n, m, a[N], d[N * 2], ans[N];
struct node {
int x, y;
}b[N * 2];
int tot, final[N], to[N], next[N], num[N];
struct Ans {
int en, g;
}c[N];
void link(int x, int y, int z) {
next[++ tot] = final[x]; to[tot] = y; num[tot] = z; final[x] = tot;
}
int final2[N], to2[N], next2[N], tot2;
void link2(int x, int y) {
next2[++ tot2] = final2[x]; to2[tot2] = y; final2[x] = tot2;
}
int z2[N], z0;
void dg(int x, int en) {
z0 = 1; d[1] = x; z2[1] = 0;
while(z0 > 0) {
int bx = 0;
if(z2[z0] == 0) {
x = d[z0];
for(int i = final[x]; i; i = next[i]) {
int y = to[i], z = num[i];
for(int l = 1, r = z0; l <= r; ) {
int m = (l + r) / 2;
if(d[m] <= y) c[z].g = z0 - m + 1, c[z].en = d[m], r = m - 1; else l = m + 1;
}
}
for(int i = final2[x]; i; i = next2[i]) {
z2[z0] = i, d[++ z0] = to2[i], z2[z0] = 0;
bx = 1; break;
}
} else {
for(int i = next2[z2[z0]]; i; i = next2[i]) {
z2[z0] = i, d[++ z0] = to2[i], z2[z0] = 0;
bx = 1; break;
}
}
if(!bx) z0 --;
}
}
int bz[N];
void Solve() {
int st = 1, en = 0;
memset(bz, 0, sizeof(bz));
memset(final2, 0, sizeof(final2));
memset(next2, 0, sizeof(next2));
tot2 = 0;
fd(i, n, 1) {
while(st <= en && a[d[en]] < a[i]) en --;
if(st > en) bz[i] = 1; else link2(d[en], i);
d[++ en] = i;
}
fo(i, 1, n) if(bz[i])
d[1] = i, dg(i, 1);
}
int main() {
freopen("trip.in", "r", stdin);
freopen("trip.out", "w", stdout);
scanf("%d %d", &n, &m);
fo(i, 1, n) read(a[i]);
fo(i, 1, m) read(b[i].x), read(b[i].y);
fo(i, 1, m) link(b[i].x, b[i].y, i);
Solve();
memset(final, 0, sizeof(final));
memset(next, 0, sizeof(next));
tot = 0;
fo(i, 1, m) {
ans[i] = c[i].g;
c[i].g = 0;
if(c[i].en < b[i].y) link(n - b[i].y + 1, n - c[i].en, i);
}
fo(i, 1, n / 2) swap(a[i], a[n - i + 1]);
Solve();
fo(i, 1, m) ans[i] += c[i].g, write(ans[i]);
}