傳送門
開始想的是用樹剖來維護
但發現因為對每個人都不一樣而且又要一直修改,不是很好維護
其實也是可以維護的
按照點的dfs
dfsdf
s序從上往下列舉
然後每個點都用樹剖向其到根的路徑上打上自己屬性的標記
這樣相當於每個人就都有走到根的比較了,直接二分找到第乙個跑不了的位置
複雜度o(n
logm
2+ml
ogm2
)o(nlogm^2+mlogm^2)
o(nlog
m2+m
logm
2)但顯然很不好寫,碼量窒息,樹剖+線段樹區間加區間乘區間最大值
還是啟發式合併好寫點
在洛谷上看到了一篇優先佇列啟發式合併的
思路很不錯
確實比左偏樹要簡單許多(c++stl萬歲!)
**:
#include
using
namespace std;
#define ll long long
#define double long double
inline
intread()
while
(isdigit
(ch)
)res=
(res<<3)
+(res<<1)
+(ch^48)
,ch=
getchar()
;return res*f;
}inline ll readl()
while
(isdigit
(ch)
)res=
(res<<3)
+(res<<1)
+(ch^48)
,ch=
getchar()
;return res*f;
}const
int n=
600005
;int adj[n]
,rt[n]
,n,m,nxt[n]
,to[n]
,fa[n]
,dep[n]
,ans[n]
,cnt,a[n]
,st[n]
,des[n]
;ll h[n]
,v[n]
,add[n]
,mul[n]
;struct knt
;priority_queueq[n]
;inline
bool
operator
<
(const knt&a,
const knt&b)
inline ll get
(double x)
inline
void
addedge
(int u,
int v)
inline
void
merge
(int u,
int v));
}}inline
void
dfs(
int u)
while
(q[rt[u]].
size()
)if(!a[u]
)add[rt[u]]+
=v[u]
;else mul[rt[u]]*
=v[u]
,add[rt[u]]*
=v[u];}
intmain()
for(
int i=
2;i<=n;i++
)for
(int i=
1;i<=m;i++))
;}dfs(1)
;for
(int i=
1;i<=n;i++
)for
(int i=
1;i<=n;i++
)for
(int i=
1;i<=m;i++
)exit(0
);}
JLOI2015 城池攻占
霧.改變操作乘法是沒有負數的,那麼就不會改變大小關係,我們就可以dfs樹,然後用可合併堆進行操作。splay 啟發式合併也可以過 luogu 3261 bzoj 4003 include include include define int long long const int maxm 3100...
JLOI2015 城池攻占
點此看題 先把每個人放到對應的點上,可以用左偏樹,然後從下往上合併,每次就刪除當前節點會犧牲的人,然後維護乙個 加法 乘法 標記,時間複雜度o n log n o n log n o nlogn include include using namespace std define int long ...
JLOI2015 城池攻占
原題位址 首先發現乘的時候 係數不會為負,所以能得到乙個關鍵條件 變化後的戰鬥力隨變化前的戰鬥力大小單調 所以我們考慮倍增 設hp x i 是從x開始一路攻克 2 i 個城池所需要最小的初始生命值 設trans x i 0 1 是攻克了 2 i 個城池後攻擊力的變化量,0表示乘,1表示加,先乘後加 ...