4826: [Hnoi2017]影魔

https://lydsy.com/JudgeOnline/problem.php?id=4826

分析:

  莫队+单调栈+st表。

  考虑如何O(1)加入一个点,删除一个点,类似bzoj4540。然后就可以莫队了。复杂度$O(n\sqrt n)$

代码:

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL; char buf[], *p1 = buf, *p2 = buf;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
inline int read() {
int x=,f=;char ch=nc();for(;!isdigit(ch);ch=nc())if(ch=='-')f=-;
for(;isdigit(ch);ch=nc())x=x*+ch-'';return x*f;
} const int N = ;
struct Edge{
int l, r, bel, id;
bool operator < (const Edge &A) const {
return bel == A.bel ? r < A.r : bel < A.bel;
}
}Q[N];
int cnt[N], a[N], f[N][], Log[N];
int sum1R[N], sum1L[N], sum2R[N], sum2L[N], q[N], mxL[N], mxR[N];
int P1, P2, L, R, n, m;
LL ans[N], Ans = ; int getmax(int l,int r) {
int k = Log[r - l + ];
int p1 = f[l][k], p2 = f[r - ( << k) + ][k];
return a[p1] > a[p2] ? p1 : p2;
} void updR(int x,int f) {
if (L >= R) { Ans = ; return ; }
int p = getmax(L, R - ), p2 = max(mxL[x], p);
Ans += (sum1L[R - ] - sum1L[p2] + ) * P1 * f;
Ans += (sum1L[p2] - sum1L[p]) * P2 * f;
Ans += (sum2L[R - ] - sum2L[p2]) * P2 * f;
if (L > mxL[x]) Ans += (p2 - L) * P2 * f;
} void updL(int x,int f) {
if (L >= R) { Ans = ; return ; }
int p = getmax(L + , R), p2 = min(mxR[x], p);
Ans += (sum1R[L + ] - sum1R[p2] + ) * P1 * f;
Ans += (sum1R[p2] - sum1R[p]) * P2 * f;
Ans += (sum2R[L + ] - sum2R[p2]) * P2 * f;
if (R < mxR[x]) Ans += (R - p2) * P2 * f;
} int main() {
n = read(), m = read();P1 = read(), P2 = read();
int B = sqrt(n);
for (int i = ; i <= n; ++i) a[i] = read(), f[i][] = i;
for (int j = ; ( << j) <= n; ++j) {
for (int i = ; i + ( << j) - <= n; ++i) {
int p1 = f[i][j - ], p2 = f[i + ( << (j - ))][j - ];
f[i][j] = a[p1] > a[p2] ? p1 : p2;
}
}
Log[] = -;
for (int i = ; i <= n; ++i) Log[i] = Log[i >> ] + ;
a[] = a[n + ] = 1e9;
int l = , r = ; q[] = ;
for (int i = ; i <= n; ++i) {
while (l <= r && a[i] > a[q[r]]) r --;
q[++r] = i;
int j = q[r - ]; mxL[i] = j;
sum2L[i] = sum2L[j] + (i - j - ); sum1L[i] = sum1L[j] + ;
}
l = , r = ; q[] = n + ;
for (int i = n; i >= ; --i) {
while (l <= r && a[i] > a[q[r]]) r --;
q[++r] = i;
int j = q[r - ]; mxR[i] = j;
sum2R[i] = sum2R[j] + (j - i - ); sum1R[i] = sum1R[j] + ;
}
for (int i = ; i <= m; ++i) {
Q[i].l = read(), Q[i].r = read(), Q[i].bel = (Q[i].l - ) / B + , Q[i].id = i;
}
sort(Q + , Q + m + );
L = , R = ;
for (int i = ; i <= m; ++i) {
while (L > Q[i].l) L --, updL(L, );
while (R < Q[i].r) R ++, updR(R, );
while (L < Q[i].l) updL(L, -), L ++;
while (R > Q[i].r) updR(R, -), R --;
ans[Q[i].id] = Ans;
}
for (int i = ; i <= m; ++i) printf("%lld\n", ans[i]);
return ;
}

sol2:

  每个点i找到左边右边第一个比它大的点,设为x,y,那么x,y会产生P1的贡献,x和[i+1,y-1],y和[x+1,i-1]会产生P2的贡献,把它们看做是平面上的点,然后转化为二维数点问题。

  询问区间L,R,就是询问横坐标在[L,R]的,纵坐标也在[L,R]的点有多少个。有一个问题:(y,x+1)这个点是否和(x+1,y)的贡献一样?就是这两个数哪个在前面的问题,因为询问总是一个关于直线y=x对称的一个矩形,而(y,x+1)和(x+1,y)也关于y=x对称,所以这两个点怎么放都行。

  然后离线+扫描线+线段树就行了(可以标记永久化)。复杂度$O(nlogn)$

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#define Root 1, n, 1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
struct Node{
int p, l, r, id, w;
bool operator < (const Node &A) const { return p < A.p; }
}q[N * ], A[N * ];
int L[N], R[N], sk[N], a[N];
LL sum[N << ], tag[N << ], ans[N]; void update(int l,int r,int rt,int L,int R,int v) {
sum[rt] += 1ll * (R - L + ) * v;
if (L == l && r == R) {
tag[rt] += v; return ;
}
int mid = (l + r) >> ;
if (R <= mid) update(lson, L, R, v);
else if (L > mid) update(rson, L, R, v);
else update(lson, L, mid, v), update(rson, mid + , R, v);
}
LL query(int l,int r,int rt,int L,int R,LL t) {
if (L == l && r == R) return sum[rt] + 1ll * (R - L + ) * t;
int mid = (l + r) >> ;
if (R <= mid) return query(lson, L, R, t + tag[rt]);
else if (L > mid) return query(rson, L, R, t + tag[rt]);
else return query(lson, L, mid, t + tag[rt]) + query(rson, mid + , R, t + tag[rt]);
}
int main() {
int n = read(), m = read(), P1 = read(), P2 = read();
for (int i = ; i <= n; ++i) a[i] = read();
for (int top = , i = ; i <= n; ++i) {
while (top && a[i] > a[sk[top]]) top --;
sk[++top] = i;
L[i] = sk[top - ];
}
sk[] = n + ;
for (int top = , i = n; i >= ; --i) {
while (top && a[i] > a[sk[top]]) top --;
sk[++top] = i;
R[i] = sk[top - ];
}
int tot = ;
for (int i = ; i <= n; ++i) {
if (L[i] && R[i] <= n) A[++tot] = (Node){R[i], L[i], L[i], , P1};
if (L[i] && R[i] > i + ) A[++tot] = (Node){L[i], i + , R[i] - , , P2};
if (R[i] <= n && i > L[i] + ) A[++tot] = (Node){R[i], L[i] + , i - , , P2};
}
for (int i = ; i <= m; ++i) {
int l = read(), r = read();
q[i] = (Node){l - , l, r, i, -};
q[i + m] = (Node){r, l, r, i, };
ans[i] += 1ll * (r - l) * P1;
}
sort(q + , q + m + m + );
sort(A + , A + tot + );
int now = ;
while (A[now].p <= ) now ++;
for (int i = ; i <= m + m; ++i) {
while (now <= tot && A[now].p <= q[i].p) {
update(Root, A[now].l, A[now].r, A[now].w); now ++;
}
ans[q[i].id] += 1ll * query(Root, q[i].l, q[i].r, ) * q[i].w;
}
for (int i = ; i <= m; ++i) printf("%lld\n", ans[i]);
return ;
}

4826: [Hnoi2017]影魔的更多相关文章

  1. bzoj 4826: [Hnoi2017]影魔 [主席树 单调栈]

    4826: [Hnoi2017]影魔 题意:一个排列,点对\((i,j)\),\(p=max(i+1,j-1)\),若\(p<a_i,a_j\)贡献p1,若\(p\)在\(a_1,a_2\)之间 ...

  2. BZOJ:4826: [Hnoi2017]影魔

    Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵 ...

  3. ●BZOJ 4826 [Hnoi2017]影魔

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4826 题解: 主席树,单调栈 以前还没做过这种维护信息的题,感觉好奇妙. 每对相邻的两个数所 ...

  4. BZOJ 4826: [Hnoi2017]影魔 单调栈 主席树

    https://www.lydsy.com/JudgeOnline/problem.php?id=4826 年少不知空间贵,相顾mle空流泪. 和上一道主席树求的东西差不多,求两种对 1. max(a ...

  5. BZOJ 4826: [Hnoi2017]影魔 单调栈+可持久化线段树

    Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个 ...

  6. BZOJ 4826 [Hnoi2017]影魔 ——扫描线 单调栈

    首先用单调栈和扫描线处理出每一个数左面最近的比他大的数在$l[i]$,右面最近的比他大的数$r[i]$. 然后就可以考虑每种贡献是在什么时候产生的. 1.$(l[i],r[i])$产生$p1$的贡献 ...

  7. bzoj 4826: [Hnoi2017]影魔【单调栈+树状数组+扫描线】

    参考:https://www.cnblogs.com/lcf-2000/p/6789680.html 这是一个相对码量少的做法,用到了区间修改区间查询的树状数组,详见:www.cnblogs.com/ ...

  8. [BZOJ4826][HNOI2017]影魔(主席树)

    4826: [Hnoi2017]影魔 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 669  Solved: 384[Submit][Status][ ...

  9. 【LG3722】[HNOI2017]影魔

    [LG3722][HNOI2017]影魔 题面 洛谷 题解 先使用单调栈求出\(i\)左边第一个比\(i\)大的位置\(lp_i\),和右边第一个比\(i\)大的位置\(rp_i\). 考虑\(i\) ...

随机推荐

  1. MR数据生成工具指向目录

    mrDataTidy_SaveTwoDays.jar 原始路径 :D:\太原MR数据\一天数据整理 目标路径 : D:\MR现场数据整理\保存两天_整理后数据 例如 当前时间:2017-5-17 10 ...

  2. ARMV8 datasheet学习笔记4:AArch64系统级体系结构之编程模型(3)- 异常

    1.前言 本文介绍异常相关内容,包括异常类型,异常进入,异常返回,异常层次结构,异常的路由等 2.  RESET ARMV8体系结构支持两种类型的RESET Cold reset:Reset PE所有 ...

  3. 【bzoj1901】dynamic ranking(带修改主席树)

    传送门(权限) 传送门(非权限) 花了一晚上总算把代码调好了……才知道待修改主席树怎么操作…… 然而还是一知半解orz…… 先说说我的理解吧 我们一般建主席树的时候都是直接在序列上建的 但是如果有修改 ...

  4. oracle ip 改为 机器名

    1 hosts文件 添加                   ip  机器名   这一行 2 修改listner.ora 和tnsora.ora ip改为机器名 3 重启服务

  5. Python-HTML CSS 练习

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. android录音实现不再担心—一个案例帮你解决你的问题

    最近有小伙伴经常android的录音怎么实现,有没有相关的案例.今天给大家推荐一个android中实现录音和播放的小案例. 效果图: 一.实现录音的 Service 关键代码: // 开始录音 pub ...

  7. OCM_第十三天课程:Section6 —》数据库性能调优 _结果缓存 /多列数据信息采集统计/采集数据信息保持游标有效

    注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...

  8. v-bind绑定属性样式——class的三种绑定方式

    1.布尔值的绑定方式 <div id="demo"> <span v-bind:class="{‘class-a‘:isA ,‘class-b‘:isB ...

  9. 【linux】tcpdump抓包

    tcpdump -i eth0 host 192.168.11.22 -w ./target.cap 上面指令,抓取eth0中与192.168.11.22相关的流量,保存到target.cap中

  10. bzoj1208splay模板题

    想试下新找的板子,没想到交上去CE了..懒得调..以后有机会就改 /* 用type标记当前树上的是宠物还是人 每次求前驱后缀,删掉最近的那个点 */ #include<iostream> ...