1. 程式人生 > >[bzoj4826][亂搞][樹狀陣列]影魔

[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

題解

提供兩個做法…
第一個是個 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(
            
           

相關推薦

[bzoj4826][][陣列]

Description 影魔,奈文摩爾,據說有著一個詩人的靈魂。事實上,他吞噬的詩人靈魂早已成千上萬。千百年來,他收集了各式各樣 的靈魂,包括詩人、牧師、帝王、乞丐、奴隸、罪人,當然,還有英雄。每一個靈魂,都有著自己的戰鬥力,而影魔,靠 這些戰鬥力提升自己的攻擊。奈文摩爾有

2018.10.29 bzoj3718: [PA2014]Parking(陣列

傳送門 顯然只用判斷兩個會相交的車會不會卡住就行了。 直接樹狀陣列維護字尾最大值就行了。 程式碼: #include<bits/stdc++.h> using namespace std; const int N=5e4+5; struct Matrix{int x1,x

異或和(權值陣列

異或和(權值樹狀陣列) 題目描述 在加里敦中學的小明最近愛上了數學競賽,很多數學競賽的題都是與序列的連續和相關的。所以對於一個序列,求出它們所有的連續和來說,小明覺得十分的簡單。但今天小明遇到了一個序列和的難題,這個題目不僅要求你快速的求出所有的連續和,還要快速的求出這些連續和的異或值。小明很快的就求出了

poj 3321 dfs序 陣列 前向星

  題意概括 有一顆01樹,以結點1為樹根,一開始所有的結點權值都是1,有兩種操作:   1.改變其中一個結點的權值(0變1,1變0)   2.詢問子樹X的節點權值和。 參考部落格 http://www.cnblogs.com/zhouzhendong/p/7265431.htm

淺談陣列(解析+模板)

也不知道是什麼時候開始,對於曾經學過的演算法都不太用了 遇到區間修改,區間最值就知道用線段樹,什麼樹狀陣列啊,st表啊都忘得差不多了 最近幾次模考被卡翻了,於是又想起這些老朋友 來填個坑   首先我們要明確一點,樹狀陣列只能維護求和,不能維護區間最值 樹狀陣列利用了分治的思想,層數為

hdu4325-Flowers-陣列+離散化

Flowers Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 3687   

【非原創】codeforces 1070C Cloud Computing 【線段&陣列

題目:戳這裡 學習部落格:戳這裡 題意:有很多個活動,每個活動有持續天數,每個活動會在每天提供C個CPU每個CPU價格為P,問需要工作N天,每天需要K個CPU的最少花費。 解題思路:遍歷每一天,維護當前天K個cpu的最小花費。具體方法是維護兩個線段樹(樹狀陣列也可以),維護每一天可以使用的cpu數和價格

hust1433-陣列-2

http://acm.hust.edu.cn/JudgeOnline/problem.php?id=1433 題意:給定一個1...n的排列,對i<=k<j. ans[k]為a[i]>a[j]的對數,求ans[1...n-1]。。。   分析:用樹狀陣列,求出

[zoj4046][陣列求逆序(強化版)]

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4046 題意:有一個含有n個元素的數列p,每個元素均不同且為1~n中的一個,求出將數列變為迴圈遞增序列至少需要左右相鄰的數交換多少次 題目分析:先看簡化版的題目:如果只有1 2 3

陣列【洛谷P3586】 [POI2015]LOG

P3586 [POI2015]LOG 維護一個長度為n的序列,一開始都是0,支援以下兩種操作:1.U k a 將序列中第k個數修改為a。2.Z c s 在這個序列上,每次選出c個正數,並將它們都減去1,詢問能否進行s次操作。每次詢問獨立,即每次詢問不會對序列進行修改。 離散化按照權值建立樹狀陣列

codeforces869EThe Untended Antiquity(二維陣列

/* 二維樹狀陣列+Hash 題意: 給一個地圖(n,m) 三種操作: 1,在以(r1,c1)、(r2,c2)為對角的矩形四條邊上新增障礙 2,消除以(r1,c1)、(r2,c2)為對角的矩形四條邊上的障礙 3,判斷(r1,c1)到(r2,c2)是否存在一條路徑,不經過障礙 利用二維樹

[BZOJ4240]有趣的家庭菜園(貪心+陣列)

最後數列一定是單峰的,問題就是最小化最後的位置序列的逆序對數。 從大到小加數,每次貪心看放左邊和右邊哪個產生的逆序對數更少,樹狀陣列即可。 由於大數放哪對小數不產生影響,所以正確性顯然。 注意相同數之間一定能不構成逆序對,需要特判。 1 #include<cstdio> 2 #

【11.2校內測試】【壓】【矩陣字首和】【陣列逆序對(題意轉換)】

Solution 簽到水題,直接狀壓列舉所有情況算出答案即可。 Code #include<bits/stdc++.h> #define LL long long using namespace std; inline LL read() { LL x =

離散化及陣列求逆序對

用樹狀陣列求逆序對的時候注意:要統計b[i]-1的字首和,因為可能有相同值的元素 不去重離散化: sort(a+1, a+n+1, cmp); for(int i=1; i<=n; i++) { if(i == 1 || a[i].val != a[i-1].val) { to

逆序對的三種求法(歸併排序,陣列,線段)

求逆序對個數的三種方法 逆序對: 對於一個序列 $a_1$,$a_2$,$a_3$..$a_n$,如果存在$a_i$>$a_j$且i<j,則$a_i$和$a_j$為一個逆序對。 這裡將介紹3種求逆序對對數的方法。 在此之前,預設為你已經會了歸併排序,樹狀陣列和線段樹。(不會的可以百度學習一下)

【bzoj4240】 有趣的家庭菜園 陣列

這一題最終要構造的序列顯然是一個單峰序列 首先有一個結論:一個序列通過交換相鄰的元素,進行排序,最少的交換次數為該序列的逆序對個數 (該結論很久之前打表意外發現的,沒想到用上了。。。。。) 考慮如何構造這個單峰序列 首先最大的數肯定是該序列的峰,餘下的元素我們從大到小列舉,判斷將其加入到當前序列的左邊

Luogu P3258 松鼠的新家(鏈剖分+線段/陣列

題面 題解   這種題目一看就是重鏈剖分裸題,還是區間修改,單點查詢,查詢之前在遍歷時要記一個\(delta\),因為這一次的起點就是上一次的終點,不需要放糖,所以可以用\(BIT\)來寫,但我寫完\(modify\)才反應過來,所以沒改了。 #include <cstdio> #inclu

【bzoj2789】 Letters 陣列

又是一道樹狀陣列求逆序對的題目。 這一題我們可以將第二個串中的每一個字母,與第一個串中的字母做兩兩匹配,令第二個串第i個字母的值id[i]為該字母與第一個串中的字母匹配到的位置。 然後考慮到所求答案為最小的移動次數,那麼這個最小的移動次數顯然為序列id的逆序對個數。 樹狀陣列求一求就沒了。 我一看時間

ACM-ICPC 2018 瀋陽賽區網路預賽 J. Ka Chang (分塊+陣列+dfs序)

題意 給你一顆樹,由兩種操作: 1.把這棵樹深度為 D D D的點全部都加上一個值。 2.求以p為根節點的子樹的權值和是多少? 思路 對於樹上的東西,我們可以把他求一下DFS序,之後就可以把樹上的結構變成

HUD 6447 YJJ's Salesman (dp + 陣列優化)

題意 給你一張 109∗109 10 9 ∗ 10