[bzoj4826][乱搞][树状数组]影魔

版权声明:蒻蒟的bolg... https://blog.csdn.net/Rose_max/article/details/85238889

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

题解

提供两个做法…
第一个是个 N N N\sqrt N 的莫队…大致和hnoi2016的序列差不多
还是可以通过相邻最大值建出树来搞…可以利用关键点的性质来做到 O ( 1 ) O(1) 修改
只不过我的常数巨大…
第二个大概是不同于网上大部分做法的…
我们可以定义第三类数对 ( i , j ) (i,j) ,满足 m a x ( i , j ) &gt; m x [ i + 1 ] [ j 1 ] max(i,j)&gt;mx[i+1][j-1] ,其中 m x [ i ] [ j ] mx[i][j] [ i , j ] [i,j] 的最大值
容易发现,第二类数对其实就等于第三类数对减去第一类数对
预处理前一个比他大的数的位置 p 1 [ i ] p1[i] ,后一个比他大的数的位置 p 2 [ i ] p2[i]
不妨先考虑 c a l i &lt; c a l j , i &lt; j cal_i&lt;cal_j,i&lt;j 的情况怎么算
考虑一下第一类数可以怎么找出,显然对于一个 i i ,合法的只有 ( i , p 1 [ i ] ) (i,p1[i])
如果固定了 i i ,那么 j j 的范围在 [ i + 1 , p 2 [ i ] 1 ] [i+1,p2[i]-1]
如果固定了 j j ,那么 i i 的范围在 [ p 1 [ j ] + 1 , j 1 ] [p1[j]+1,j-1]
再考虑第三类数怎么找出
离线扫右端点,扫到一个点 i i 就把 [ p 1 [ i ] + 1 , i 1 ] [p1[i]+1,i-1] 全部+1,顺便把 p 1 [ i ] p1[i] 的权在另一个数组里更新
找到一个询问就查询右端点在 r r 以内,左端点在 l , r l,r 的第一类数和第三类数
c a l i &gt; c a l j cal_i&gt;cal_j 的反过来做就好了…
扔两个代码把…

没卡过的莫队

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
inline int _min(int x,int y){return x<y?x:y;}
inline int _max(int x,int y){return x>y?x:y;}
const int MAXN=200005;
int mn[20][MAXN],bin[25],Log[MAXN+10],cal[MAXN],n,m;
void init()
{
	for(int i=1;i<=n;i++)mn[0][i]=i;
	for(int i=1;bin[i]<=n;i++)
		for(int x=1;x+bin[i]-1<=n;x++)
			mn[i][x]=cal[mn[i-1][x]]>cal[mn[i-1][x+bin[i-1]]]?mn[i-1][x]:mn[i-1][x+bin[i-1]];
}
inline int getmax(int l,int r)
{
	int K=Log[r-l+1];
	return cal[mn[K][l]]>cal[mn[K][r-bin[K]+1]]?mn[K][l]:mn[K][r-bin[K]+1];
}

//-----------------  rmq  ------------------
int p1[MAXN],dep1[MAXN];//右边第一个比我大的是谁   我在这棵树里深度多少    
int p2[MAXN],dep2[MAXN];//左边第一个比我大的是谁   我在这棵树里深度多少    
LL c1,c2;//dep1 前缀和   dep2前缀和 
int sta[MAXN],tp;

struct ask{int l,r,op;}w[MAXN];int block,pos[MAXN];
bool cmp(ask n1,ask n2){return pos[n1.l]==pos[n2.l]?n1.r<n2.r:pos[n1.l]<pos[n2.l];}
LL ans,answer[MAXN];int u1,u2,u3;
inline void mdl(int now,int r,int op)
{
	if(now>=r){ans=0;return ;}
	int o=getmax(now,r);
	ans+=_max(0,dep1[now]-dep1[o]-1)*c2*op;
	r=_min(r,p1[now]);
	u1=r-now;o=getmax(now+1,r);
	u3=dep1[now+1]-dep1[o]+1;
	u2=u1-u3;
	ans+=(LL)u2*c2*op+u3*c1*op;
}
inline void mdr(int l,int now,int op)
{
	if(l>=now){ans=0;return ;}
	int o=getmax(l,now);
	ans+=_max(0,dep2[now]-dep2[o]-1)*c2*op;
	l=_max(l,p2[now]);
	u1=now-l;o=getmax(l,now-1);
	u3=dep2[now-1]-dep2[o]+1;
	u2=u1-u3;
	ans+=(LL)u2*c2*op+u3*c1*op;
}
int main()
{
	bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
	Log[1]=0;for(int i=2;i<=MAXN;i++)Log[i]=Log[i>>1]+1;
	n=read();m=read();c1=read();c2=read();
	
	block=sqrt(n+1);
	for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1;
	
	for(int i=1;i<=n;i++)cal[i]=read();
	init();
	for(int i=1;i<=n;i++)
	{
		while(tp&&cal[sta[tp]]<cal[i])tp--;
		if(!tp)p2[i]=0;else p2[i]=sta[tp];
		sta[++tp]=i;
	}
	tp=0;
	for(int i=n;i>=1;i--)
	{
		while(tp&&cal[sta[tp]]<cal[i])tp--;
		if(!tp)p1[i]=n+1;else p1[i]=sta[tp];
		sta[++tp]=i;
	}
	for(int i=1;i<=n;i++)dep2[i]=dep2[p2[i]]+1;
	for(int i=n;i>=1;i--)dep1[i]=dep1[p1[i]]+1;
	
	for(int i=1;i<=m;i++)w[i].l=read(),w[i].r=read(),w[i].op=i;
	sort(w+1,w+1+m,cmp);
	
	int l=w[1].l,r=w[1].r;
	for(int i=w[1].l;i<=w[1].r;i++)
		mdr(l,i,1);
	answer[w[1].op]=ans;
	for(int i=2;i<=m;i++)
	{
		while(r<w[i].r)mdr(l,++r,1);
		while(l>w[i].l)mdl(--l,r,1);
		while(r>w[i].r)mdr(l,r--,-1);
		while(l<w[i].l)mdl(l++,r,-1);
		answer[w[i].op]=ans;
	}
	
	for(int i=1;i<=m;i++)pr2(answer[i]);
	return 0;
}

标程

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=200005;
LL s[2][MAXN],bit[MAXN];
int n,m,cal[MAXN];
int lowbit(int x){return x&-x;}
void ch(int x,LL c,int op){if(!x)return ;for(;x<=n;x+=lowbit(x))s[op][x]+=c;}
LL findsum(int x,int op){LL ret=0;for(;x>=1;x-=lowbit(x))ret+=s[op][x];return ret;}

void ch1(int x,int c){if(!x)return ;for(;x<=n;x+=lowbit(x))bit[x]+=c;}
LL getsum(int x){LL ret=0;for(;x>=1;x-=lowbit(x))ret+=bit[x];return ret;}
void modify(int l,int r,int c)
{
	if(l>r)return ;
	ch(l,c,0);ch(l,(LL)c*l,1);
	ch(r+1,-1,0);ch(r+1,(LL)-c*(r+1),1);
}
LL query(int l,int r)
{
	LL s1=(findsum(r,0)-findsum(l-1,0))*(r+1),s3=findsum(l-1,0);
	LL s2=findsum(r,1)-findsum(l-1,1);
	return s1-s2+s3*(r-l+1);
}

//--------------  Bit ------------
vector<pii> vec1[MAXN],vec2[MAXN],vec3[MAXN],vec4[MAXN];
LL c1,c2;
int p1[MAXN],p2[MAXN],sta[MAXN],tp;
LL ct1[MAXN],ct2[MAXN];
void work()
{
	for(int i=1;i<=n;i++)
	{
		int u=p1[i];ch1(u,1);
		modify(u+1,i-1,1);
		for(int j=0;j<vec3[i].size();j++)
		{
			int l=vec3[i][j].first,r=i,op=vec3[i][j].second;
			ct1[op]+=getsum(r)-getsum(l-1);
			ct2[op]+=query(l,r);
		}
	}
	memset(s,0,sizeof(s));memset(bit,0,sizeof(bit));
	for(int i=n;i>=1;i--)
	{
		int u=p2[i];ch1(u,1);
		modify(i+1,u-1,1);
		for(int j=0;j<vec2[i].size();j++)
		{
			int l=i,r=vec2[i][j].first,op=vec2[i][j].second;
			ct1[op]+=getsum(r)-getsum(l-1);
			ct2[op]+=query(l,r);
		}
	}
}
int main()
{
//	freopen("1.in","r",stdin);
//	freopen("a.out","w",stdout);
	n=read();m=read();c1=read();c2=read();
	for(int i=1;i<=n;i++)cal[i]=read();
	for(int i=1;i<=n;i++)
	{
		while(tp&&cal[sta[tp]]<cal[i])tp--;
		p1[i]=sta[tp];sta[++tp]=i;
	}
	tp=0;
	for(int i=n;i>=1;i--)
	{
		while(tp&&cal[sta[tp]]<cal[i])tp--;
		p2[i]=sta[tp];if(!p2[i])p2[i]=n+1;
		sta[++tp]=i;
	}
	
	for(int i=1;i<=n;i++)vec1[p1[i]].push_back(mp(i,p2[i])),vec4[p2[i]].push_back(mp(i,p1[i]));
	for(int i=1;i<=m;i++)
	{
		int a=read(),b=read();
		vec2[a].push_back(mp(b,i));
		vec3[b].push_back(mp(a,i));
	}
	work();
	for(int i=1;i<=m;i++)pr2(ct1[i]*c1+(ct2[i]-ct1[i])*c2);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/85238889