洛谷P3261 JLOI2015 城池攻占

2022-02-01 19:46:55 字數 1964 閱讀 9368

思路分析:由於這道題的資料範圍是n,m<=3e5,所以我們直接輸入乙個模擬乙個是會超時的,但是我們可以在輸入所有的士兵之後把同在乙個節點的士兵一起處理,我們可以考慮建乙個堆,從深度最大的節點開始,維護乙個節點內的士兵的最小戰鬥力值,如果戰鬥力最小的士兵都能存活下來,那麼在堆中的其他士兵一定可以活下來,之後我們在處理完乙個節點後要把這個節點中所有存活的士兵都移到它的父親節點之中,但由於父親節點之中可能也存在士兵(即從該節點開始),那麼我們就需要把這兩個堆裡面的元素合併在一起,於是我們想到用可並堆,即左偏樹,來維護和解決這個問題,我們記錄每個士兵開始和陣亡(或活到最後)的位置,之後第二部分的答案就是開始的深度減去陣亡的深度。

另外在寫左偏樹的時候,我們合併時有一步是當前節點的距離是右兒子的距離加一(符合左偏樹的性質),但在寫的時候蒟蒻發現好像讓節點的距離為左兒子的距離加一好像也可以過,後來問gjk大佬,說這樣也是可以的,只是時間複雜度好像從log

級別退化為了根號級別的。

**:

1 #include2 #include3 #include4

using

namespace

std;

5 typedef long

long

ll;6

const

int n=3e5+10;7

ll n,m;

8ll fa[n],c[n],a[n],rt[n];

9ll h[n],v[n],s[n];

10ll ls[n],rs[n],dep[n];

11ll dep[n],die[n],ans[n];

12ll add[n],cheng[n];

13void push_down(ll x)

22if

(rs[x])

29 add[x]=0,cheng[x]=1;30

}31 ll merge(ll x,ll y)

4243

intmain()

50 dep[1]=1;dep[0]=-1;//

dep是深度,dep是樹高

51for(int i=2;i<=n;++i)

55for(int i=1;i<=m;++i)

61for(int i=n;i>=1;i--)

69else

break;70

}71if(i==1) break;72

if(rt[i]==-1) continue;73

if(a[i]) cheng[rt[i]]*=v[i],add[rt[i]]*=v[i],s[rt[i]]*=v[i];

74else add[rt[i]]+=v[i],s[rt[i]]+=v[i];

75push_down(rt[i]);

76if(rt[fa[i]]==-1) rt[fa[i]]=rt[i]; //

存活士兵並到父親上

77else rt[fa[i]]=merge(rt[fa[i]],rt[i]);78}

79for(int i=1;i<=m;++i) //

統計答案

80 ans[die[i]]++;

81for(int i=1;i<=n;++i)

82 printf("

%lld\n

",ans[i]);

83for(int i=1;i<=m;++i)

84 printf("

%lld\n

",dep[c[i]]-dep[die[i]]);

85return0;

86 }

view code

洛谷P3261 JLOI2015 城池攻占

不得不說,這道題目是真的難,真不愧它的 省選 noi 的紫色大火題!花了我晚自習前半節課看題解,寫 又花了我半節晚自習調 真的心態 基本上改得和題解完全一樣了我才過了這道題!真的煩。沒事,那接下來我來完全把這道題搞透。part 1 理解題目 至少我一開始不知道為什麼要用左偏樹,甚至我看題解一開始也都...

洛谷P3261 JLOI2015 城池攻占

題目大意 有 n 個點的樹,第 i 個節點有乙個權值 h i m 個騎士,第 i 個騎士攻擊力為 v i 乙個騎士可以把從它開始的連續的父親中比它小的節點攻破,攻破乙個節點可以把攻擊力加或乘乙個數 乘的數大於 0 每個騎士獨立 問每個騎士可以攻破多少個點,每個點會阻擋住多少個騎士。題解 可以把所有騎...

P3261 JLOI2015 城池攻占

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