LG P3261 JLOI2015 城池攻占

2022-06-12 12:33:08 字數 1630 閱讀 1644

小銘銘最近獲得了一副新的桌遊,遊戲中需要用 m 個騎士攻占 n 個城池。這 n 個城池用 1 到 n 的整數表示。除 1 號城池外,城池 i 會受到另一座城池 fi 的管轄,其中 fi 每個城池有乙個防禦值 hi,如果乙個騎士的戰鬥力大於等於城池的生命值,那麼騎士就可以占領這座城池;否則占領失敗,騎士將在這座城池犧牲。占領乙個城池以後,騎士的戰鬥力將發生變化,然後繼續攻擊管轄這座城池的城池,直到占領 1 號城池,或犧牲為止。

除 1 號城池外,每個城池 i 會給出乙個戰鬥力變化引數 ai;vi。若 ai =0,攻占城池 i 以後騎士戰鬥力會增加 vi;若 ai =1,攻占城池 i 以後,戰鬥力會乘以 vi。注意每個騎士是單獨計算的。也就是說乙個騎士攻擊一座城池,不管結果如何,均不會影響其他騎士攻擊這座城池的結果。

現在的問題是,對於每個城池,輸出有多少個騎士在這裡犧牲;對於每個騎士,輸出他攻占的城池數量。

把每個騎士視為乙個節點,那麼對於樹上每個點,要求維護其子節點的所有可並堆

可並的小根堆上同時維護乘法和加法標記

時間複雜度$o((n+m) \log n)$

#include#include

using

namespace

std;

int n,m,fa[300005],a[300005],head[300005],tot,c[300005],rt[300005],ch[300005][2],dis[300005],ans1[300005],ans2[300005],dep[300005

];long

long h[300005],val[300005],v[300005],mlz[300005],plz[300005

];struct

edgeedge[

300005

];inline

long

long

read()

while(ch>='

0'&&ch<='

9')w=(w<<1)+(w<<3)+ch-'

0',ch=getchar();

return w*f;

}void cover(int x,long

long k,long

long b)

void pushdown(int

x)int merge(int a,int

b)void dfs(int k,int

f)int

main(),head[fa[i]]=tot;

for(int i=1;i<=m;i++)v[i]=read(),c[i]=read(),mlz[i]=1ll,rt[c[i]]=merge(rt[c[i]],i);

dfs(

1,0);

while(rt[1])pushdown(rt[1]),ans2[rt[1]]=dep[c[rt[1]]],rt[1]=merge(ch[rt[1]][0],ch[rt[1]][1

]);

for(int i=1;i<=n;i++)printf("

%d\n

",ans1[i]);

for(int i=1;i<=m;i++)printf("

%d\n

",ans2[i]);

return0;

}

[jloi2015]城池攻占

luogu 3261 JLOI2015 城池攻占

小銘銘最近獲得了一副新的桌遊,遊戲中需要用 m 個騎士攻占 n 個城池。這 n 個城池用 1 到 n 的整數表示。除 1 號城池外,城池 i 會受到另一座城池 fi 的管轄,其中 fi 中第 i 個騎士的初始戰鬥力為 si,第乙個攻擊的城池為 ci。每個城池有乙個防禦值 hi,如果乙個騎士的戰鬥力大...

P3261 JLOI2015 城池攻占

p3261 jloi2015 城池攻占 乍一看,平衡樹?其實左偏樹更好做啦 qwq 每個節點都來棵左偏樹維護最小值,dfs 往上時合併一下,要是攻不下了就把根節點刪掉,直到能攻下,對了,攻下後值會變化怎麼辦?lazy 標記一下,和線段樹同理 include includeusing namespac...

Luogu 3261 JLOI2015 城池攻占

bzoj 4003 需要實現乙個可並堆。每個點維護乙個小根堆,然後一開始把所有騎士加入到它所在的點的小根堆當中,實際上空間是 o m 的,然後我們從上到下不斷合併這個小根堆,合併完之後如果遇到堆頂小於當前城市的防禦值就彈掉堆頂順便記錄答案。對於那些攻占掉城池對騎士的貢獻的處理,可以採用打標記的方式實...