【bzoj4826】[Hnoi2017]影魔

4826: [Hnoi2017]影魔

Time Limit: 20 Sec   Memory Limit: 512 MB
Submit: 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

Sample Output

30
39
4
13
16

HINT

Source

[ Submit][ Status][ Discuss]


开始补博客!!!!


额。。这题非常的玄学

菜狗我看到这题,第一个想到的是一种玄学搞法。。。

就是先把每个点的左边比它大的离它最近的下标给弄出来。。。(反向也要)

然后发现每个点最多只有一个这样的点与它对应,把这个看成父子关系的话,整个序列可以看成一个森林


在询问区间内出现过的点,他的父亲贡献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;
}

可以用主席树搞

猜你喜欢

转载自blog.csdn.net/joky_2002/article/details/79953877