4826: [Hnoi2017]影魔
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 798 Solved: 464
[ Submit][ Status][ Discuss]
Description
影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样
的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠
这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。
第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i<j)来说,若不存在 k[s](i
<s<j)大于 k[i]或者 k[j],则会为影魔提供 p1 的攻击力(可理解为:当 j=i+1 时,因为不存在满足 i<s<j 的 s,从
而 k[s]不存在,这时提供 p1 的攻击力;当 j>i+1 时,若max{k[s]|i<s<j}<=min{k[i],k[j]} , 则 提 供 p1 的 攻
击 力 ); 另 一 种 情 况 , 令 c 为k[i+1],k[i+2],k[i+3]......k[j-1]的最大值,若 c 满足:k[i]<c<k[j],或
者 k[j]<c<k[i],则会为影魔提供 p2 的攻击力,当这样的 c 不存在时,自然不会提供这 p2 的攻击力;其他情况的
点对,均不会为影魔提供攻击力。影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任
意一段区间[a,b],1<=a<b<=n,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑 所有满足a<=i<j<=b 的灵
魂对 i,j 提供的攻击力之和。顺带一提,灵魂的战斗力组成一个 1 到 n 的排列:k[1],k[2],...,k[n]。
Input
第一行 n,m,p1,p2
第二行 n 个数:k[1],k[2],...,k[n]
接下来 m 行,每行两个数 a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
1 <= n,m <= 200000;1 <= p1,p2 <= 1000
Output
共输出 m 行,每行一个答案,依次对应 m 个询问。
Sample Input
10 5 2 3
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
Sample Output
30
39
4
13
16
39
4
13
16
HINT
Source
额。。这题非常的玄学
菜狗我看到这题,第一个想到的是一种玄学搞法。。。
就是先把每个点的左边比它大的离它最近的下标给弄出来。。。(反向也要)
然后发现每个点最多只有一个这样的点与它对应,把这个看成父子关系的话,整个序列可以看成一个森林
在询问区间内出现过的点,他的父亲贡献p1,他的祖先贡献p2(父亲和祖先都要出现在区间中),这个我当时觉得可能可以主席树维护一下?
但是1h后我发现好像并不能。。。
扫描二维码关注公众号,回复:
1654194 查看本文章
%了题解才知道大概怎么写。。。
依然是要把“每个点的左边比它大的离它最近的下标”给找出来,设为nex[i],反向设为pre[i]
然后发现,1、如果左端点为pre,右端点在[i + 1,nex - 1]范围内,则每个右端点会对答案贡献p2;2、如果右端点为nex,左端点在[pre + 1,i - 1]范围内,则每个左端点会对答案贡献p2;3、同时点对(i,nex)会对答案贡献p1
把nex看成纵坐标,pre看成横坐标,会发现询问其实就是在一个平面内求子矩形和
进一步讨论,发现这个平面内的图形无非就只有和坐标轴平行的直线
于是可以用主席树搞
然后搞一搞就做完啦。。。
ps.我主席树被卡了我会说?(bzoj比较渣,推荐先把询问离线+输出优化)
pps.csdn的修改字号好像有bug。。。每次修改成中号的时候总是会多出好几行。。
#include<cstdio> #include<vector> #include<queue> #include<ctime> #include<algorithm> #include<cstdlib> #include<stack> #include<cstring> #include<cmath> using namespace std; typedef long long LL; const int INF = 2147483647; const int maxn = 200010; const int segn = 12 * maxn; struct data{ int l,r,i; }a[maxn]; struct Q{ int l,r,id,d; }; vector<Q> q[maxn]; int n,m,b[maxn],pre[maxn],nex[maxn]; int rt,xrt,yrt,rc[segn],lc[segn],tot; int maxx[segn],minx[segn]; LL p1,p2,sum[segn],add[segn],ans[maxn]; inline LL getint() { LL ret = 0,f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar(); return ret * f; } inline void build(int o,int l,int r) { minx[o] = n + 1; maxx[o] = 0; if (l == r) return; int mid = l + r >> 1,lc = o << 1,rc = o << 1 | 1; build(lc,l,mid); build(rc,mid + 1,r); } inline void modify(int o,int l,int r,int pos,int x) { if (l == r) {maxx[o] = minx[o] = x; return;} int lc = o << 1,rc = o << 1 | 1,mid = l + r >> 1; if (pos <= mid) modify(lc,l,mid,pos,x); else modify(rc,mid + 1,r,pos,x); maxx[o] = max(maxx[lc],maxx[rc]); minx[o] = min(minx[lc],minx[rc]); } inline int querymax(int o,int l,int r,int al,int ar) { if (al <= l && r <= ar) return maxx[o]; int lc = o << 1,rc = o << 1 | 1,mid = l + r >> 1,ret = 0; if (al <= mid) ret = max(ret,querymax(lc,l,mid,al,ar)); if (mid < ar) ret = max(ret,querymax(rc,mid + 1,r,al,ar)); return ret; } inline int querymin(int o,int l,int r,int al,int ar) { if (al <= l && r <= ar) return minx[o]; int lc = o << 1,rc = o << 1 | 1,mid = l + r >> 1,ret = n + 1; if (al <= mid) ret = min(ret,querymin(lc,l,mid,al,ar)); if (mid < ar) ret = min(ret,querymin(rc,mid + 1,r,al,ar)); return ret; } inline void insert(int &o,int l,int r,int al,int ar,LL x) { if (!o) o = ++tot; sum[o] += (min(ar,r) - max(al,l) + 1) * x; if (al <= l && r <= ar) {add[o] += x; return;} int mid = l + r >> 1; if (al <= mid) insert(lc[o],l,mid,al,ar,x); if (mid < ar) insert(rc[o],mid + 1,r,al,ar,x); } inline LL query(int o,int l,int r,int al,int ar) { if (!o) return 0; if (al <= l && r <= ar) return sum[o]; int mid = l + r >> 1; LL ret = add[o] * (min(ar,r) - max(al,l) + 1); if (al <= mid) ret += query(lc[o],l,mid,al,ar); if (mid < ar) ret += query(rc[o],mid + 1,r,al,ar); return ret; } inline int cmpl(data a,data b) { return a.l < b.l; } inline int cmpr(data a,data b) { return a.r < b.r; } inline void print(LL x) { if (x >= 10) print(x / 10); putchar(x % 10 + '0'); } int main() { #ifdef AMC freopen("AMC1.txt","r",stdin); freopen("AMC2.txt","w",stdout); #endif n = getint(); m = getint(); p1 = getint(); p2 = getint(); build(1,1,n); for (int i = 1; i <= n; i++) { pre[i] = querymax(1,1,n,b[i] = getint(),n); modify(1,1,n,b[i],i); } build(1,1,n); for (int i = n; i >= 1; i--) { nex[i] = querymin(1,1,n,b[i],n); modify(1,1,n,b[i],i); } for (int i = 1; i <= n; i++) a[i].l = pre[i] , a[i].r = nex[i] , a[i].i = i; for (int i = 1; i <= m; i++) { int l = getint(),r = getint(); q[l - 1].push_back((Q){l,r,i,-1}); q[r].push_back((Q){l,r,i,1}); ans[i] += p1 * (r - l); } sort(a + 1,a + n + 1,cmpl); int now = 1; while (!a[now].l && now <= n + 1) now++; for (int i = 1; i <= n; i++) { while (a[now].l == i) { if (a[now].i + 1 <= a[now].r - 1) insert(xrt,1,n,a[now].i + 1,a[now].r - 1,p2); if (a[now].r <= n) insert(rt,1,n,a[now].r,a[now].r,p1); ++now; } for (int j = 0; j < q[i].size(); j++) { int id = q[i][j].id,d = q[i][j].d; ans[id] += d * query(rt,1,n,q[i][j].l,q[i][j].r); ans[id] += d * query(xrt,1,n,q[i][j].l,q[i][j].r); } } sort(a + 1,a + n + 1,cmpr); now = 1; for (int i = 1; i <= n; i++) { while (a[now].r == i) { if (a[now].l + 1 <= a[now].i - 1) insert(yrt,1,n,a[now].l + 1,a[now].i - 1,p2); now++; } for (int j = 0; j < q[i].size(); j++) { int id = q[i][j].id,d = q[i][j].d; ans[id] += d * query(yrt,1,n,q[i][j].l,q[i][j].r); } } for (int i = 1; i <= m; i++) print(ans[i]) , putchar('\n'); return 0; }
可以用主席树搞