[bzoj4826][亂搞][樹狀數組]影魔

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

題解

提供兩個做法…
第一個是個NNN\sqrt N的莫隊…大致和hnoi2016的序列差不多
還是可以通過相鄰最大值建出樹來搞…可以利用關鍵點的性質來做到O(1)O(1)修改
只不過我的常數巨大…
第二個大概是不同於網上大部分做法的…
我們可以定義第三類數對(i,j)(i,j),滿足max(i,j)&gt;mx[i+1][j1]max(i,j)&gt;mx[i+1][j-1],其中mx[i][j]mx[i][j][i,j][i,j]的最大值
容易發現,第二類數對其實就等於第三類數對減去第一類數對
預處理前一個比他大的數的位置p1[i]p1[i],後一個比他大的數的位置p2[i]p2[i]
不妨先考慮cali&lt;calj,i&lt;jcal_i&lt;cal_j,i&lt;j的情況怎麼算
考慮一下第一類數可以怎麼找出,顯然對於一個ii,合法的只有(i,p1[i])(i,p1[i])
如果固定了ii,那麼jj的範圍在[i+1,p2[i]1][i+1,p2[i]-1]
如果固定了jj,那麼ii的範圍在[p1[j]+1,j1][p1[j]+1,j-1]
再考慮第三類數怎麼找出
離線掃右端點,掃到一個點ii就把[p1[i]+1,i1][p1[i]+1,i-1]全部+1,順便把p1[i]p1[i]的權在另一個數組裏更新
找到一個詢問就查詢右端點在rr以內,左端點在l,rl,r的第一類數和第三類數
cali&gt;caljcal_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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章