在 c 國中有 n 位士兵,除士兵 1 外,每位士兵 i 均有且僅有一位士兵j(
jj (j
作為他的直屬教官。士兵 i 被他的直屬教官 j 以及所有能管轄 j 的士兵所管轄。每位士兵也看做能管轄自己。
每位士兵均有兩個屬性值:戰鬥力bi
b
i與領導力 li
l i。
現在 c 國要舉行 q 次閱兵,每次閱兵會指定一位士兵 s 做總指揮,士兵 s需要訓練自己所管轄的所有士兵,並以最好的精神面貌迎接閱兵式。
士兵 s 每次閱兵訓練時有一次機會(只能使用一次或不使用),可以邀請一位不受他管轄的士兵 i 來指導一位他所管轄的士兵 j,並會使得士兵 j 的戰鬥力由bj
b
j提公升為bj
+li bj+
li
,這次提公升僅對當次閱兵有效。
士兵 s 訓練出的士兵隊伍所能展現出的精神力 p 為:ma
x max
,i、j 被s管轄
現在 c 國主席想知道,每次閱兵的隊伍所能展現出的精神力 p 最大能是多少?請你幫助他。
第一行兩個數 n,q 表示士兵數以及閱兵次數。
接下來一行 n-1 個整數,第 i 個整數表示士兵 i+1 的直屬教官。
接下來 n 行每行兩個整數 bi
,li bi,
li
描述一位士兵的屬性。
接下來 q 行每行乙個整數si
s
i,表示這次閱兵的總指揮。
對於每次閱兵輸出一行乙個整數,表示閱兵隊伍能展現出的最大精神力 p。
5 2
1 1 2 2
2 1
1 5
4 2
2 3
3 1 1 2
3 37 3
1 1 2 2 3 3
3 0
1 3
5 2
2 0
4 1
3 1
2 2
1 2 35
3 40817 orz
簡化題意,即:允許將s的子樹中的乙個點加上某一權值(也可以不加),求不同方法更新後的子樹嚴格次大值的最大值。
我們記錄子樹中原來的戰鬥力最大值、次大值、第三大值分別為b0
,b1,
b2b 0,
b1,b
2,子樹外的領導力最大值、次大值為l0
,l1 l0,
l1
。要求b0
≥b1,
b1>b2
,l0>l1
b 0≥
b1,b
1>b2
,l
0>l1
當b1+l0≠
b0b 1+
l0≠b
0時,顯然將b1
b
1加上l0
l
0是最優的 當b
1+l0
=b0 b1+
l0=b
0時,顯然不能這樣加(否則mod出來是0)。於是就有兩種可能的答案:b1
+l1 b1+
l1
和l0+b
2 l0+
b2
。對兩種答案取max即可
子樹問題,可用dfs序化為序列區間問題。可以用線段樹維護子樹戰鬥力極值,用字首字尾維護不在子樹的領導力極值。
#include
#include
using namespace std
;struct dtmaxn[1110000];
struct nodefrl[222222],bel[222222];
int b[222222],l[222222];
int newid[222222];
node mex(node a,node b)
dt max(dt a,dt b)
else
return ans;
}void init(int now,int l,int r)
int mid=l+r >>1,ls=now<<1,rs=(now<<1)|1
; init(ls,l,mid);
init(rs,mid+1,r);
maxn[now]=max(maxn[ls],maxn[rs]);
}dt got(int now,int l,int r,int x,int y)
; if(x
<=mid)ans=max(ans,got(ls,l,mid,x,y));
if(y>mid)ans=max(ans,got(rs,mid+1,r,x,y));
return ans;
}int nn[222222],las[222222];
int in[222222],out[222222];
int time=0
;void dfs(int x)
int main()
; for(i=1
;i<=n;i++)
frl[i]=mex(frl[i-1],(node));
for(i=n;i;--i)
bel[i]=mex(bel[i+1],(node));
while(q--)
}return 0;}
/**/
以上**是本蒟蒻在神志不清的時候打的,實際上根本不用線段樹
dfs一下,合併即可
#include
#include
using namespace std
;struct dtans[1110000];
struct nodefrl[222222],bel[222222];
int l[222222];
int newid[222222];
node mex(node a,node b)
dt max(dt a,dt b)
else
return ans;
}int nn[222222],las[222222];
int in[222222],out[222222];
int time=0
;void dfs(int x)
out[x]=time;
}int main()
; for(i=1
;i<=n;i++)
frl[i]=mex(frl[i-1],(node));
for(i=n;i;--i)
bel[i]=mex(bel[i+1],(node));
while(q--)
}return 0
;}
士兵佇列訓練
某部隊進行新兵佇列訓練,將新兵從一開始按順序依次編號,並排成一行橫隊,訓練的規則如下 從頭開始一至二報數,凡報到二的出列,剩下的向小序號方向靠攏,再從頭開始進行一至三報數,凡報到三的出列,剩下的向小序號方向靠攏,繼續從頭開始進行一至二報數。以後從頭開始輪流進行一至二報數 一至三報數直到剩下的人數不超...
士兵佇列訓練問題
實驗任務 某部隊進行新兵佇列訓練,將新兵從一開始按順序依次編號,並排成一行橫隊,訓練的 規則如下 從頭開始一至二報數,凡報到二的出列,剩下的向小序號方向靠 攏,再從頭開 始進行一至三報數,凡報到三的出列,剩下的向小序號方向靠攏,繼續從頭開始進行一至二 報數。以後從頭開始輪流進行一至二報數 一至三報 ...
士兵佇列訓練問題
題意 hdoj1276 典型的佇列問題,入門水題 題解 第一次做普通佇列,引用了別人的演算法,優化了一下,題解記錄學到的一點東西 佇列和陣列之類的東西完全不同,和棧一樣,被固定的順序和進出卡的很死,所以在做佇列的題目時,不能像陣列一樣思維 因為是3個人,所以首先按佇列的大小來卡人數,初始化的時候,從...