[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
題解
提供兩個做法…
第一個是個 的莫隊…大致和hnoi2016的序列差不多
還是可以通過相鄰最大值建出樹來搞…可以利用關鍵點的性質來做到 修改
只不過我的常數巨大…
第二個大概是不同於網上大部分做法的…
我們可以定義第三類數對 ,滿足 ,其中 是 的最大值
容易發現,第二類數對其實就等於第三類數對減去第一類數對
預處理前一個比他大的數的位置 ,後一個比他大的數的位置
不妨先考慮 的情況怎麼算
考慮一下第一類數可以怎麼找出,顯然對於一個 ,合法的只有
如果固定了 ,那麼 的範圍在
如果固定了 ,那麼 的範圍在
再考慮第三類數怎麼找出
離線掃右端點,掃到一個點 就把 全部+1,順便把 的權在另一個數組裡更新
找到一個詢問就查詢右端點在 以內,左端點在 的第一類數和第三類數
的反過來做就好了…
扔兩個程式碼把…
沒卡過的莫隊
#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