目前只有開o2能過,stl的常數太大了,qwq
題意簡述,給你一棵樹,有點權與邊權,然後有很多詢問,每次詢問你點權在l∼r
l∼r範圍內的點到給點點v
v的距離之和。
我們使用動態點分治來求取答案。
先構建出點分樹,樹高肯定是在log
nlog
n級別內的,然後對於乙個分治點(重心),我們在上面記錄三個值:
我們維護這三個值是因為計算答案時,對於子樹內的點我們可以直接加上,對於祖先部分的點我們直接加上直接到祖先的距離,而對於其它部分的點,我們將其拆分為u→l
ca→v
u→lc
a→v兩條路來統計,然後再減去多餘的。
那麼對應的式子為s2
[u]+
∑(s2
[f[p
]]−s
3[p]
)+(s
1[f[
p]]−
s1[p
])×d
ist(
f[p]
,u)s
2[u]
+∑(s
2[f[
p]]−
s3[p
])+(
s1[f
[p]]
−s1[
p])×
dist
(f[p
],u)
其中pp
開始=u=u
,然後不斷往點分樹的根跳即可。
但是在實際的統計中,我們這樣實現:
下面上一張圖來詳細的講解一下為什麼如此計算:
我們發現對於當前要求的點u
u,如果我們p=u
p=u,那麼就直接加上當前子樹到p
p的距離和,由於還有父親,所以我們看,當p
p為父親v
v時,我們這樣操作:
那麼操作的正確性就非常顯然了。
而對於權值在l∼r
l∼r的限制,我們可以利用字首和的思想,求1∼l
−11∼
l−1和1
∼r1∼
r的答案相減即可得到,所以用乙個set
set或者vec
torv
ecto
r存下來即可(c++中的stl
stl)
那麼每次詢問時即可在點分樹上跳父親統計答案即可,複雜度為log
2nlo
g2n,預處理點分樹nlo
g2nn
log2
n,預處理lca
lca我們用rmq
rmq來,所以為nlo
gnnl
ogn,查詢lca
lca的複雜度變成o(1
)o(1
),所以總的複雜度為nlo
gn+n
log2
n+ml
og2n
nlog
n+nl
og2n
+mlo
g2n,對於2e5
2e5的資料再加上大常數,所以要開o2o
2優化。
**醜陋qaq:
#include
#include
#include
#include
#include
#define ll long long
using
namespace std;
const
int m=
5e5+10;
int n,q,a;
int age[m]
;struct ssss(
int a,
int b,ll c):to
(a),
last
(b),
len(c)
}g[m<<1]
;int head[m]
,cnt;
void
add(
int a,
int b,ll c)
struct node
node
(int a,ll b,ll c,ll d):p
(a),
s1(b),s2
(c),
s3(d)
bool
operator
<
(const node &a)
const};
vector rec[m]
;#define pb push_back
typedef vector
::iterator iter;
int pos[m]
,tim,lgp[m]
,lg;
ll lcaq[25]
[m],dis[m]
;//rmq求lca來求距離
void
dfs_rmq
(int a,
int b)
}void
init_rmq()
}}ll dist
(int a,
int b)
int sze[m]
,f[m]
,son[m]
,totsze,root;
bool vis[m]
;//找重心
void
findroot
(int a,
int fa)
if(totsze-sze[a]
>son[a]
)son[a]
=totsze-sze[a];if
(son[a]
)root=a;
}void
getall
(int a,
int fa,
int o)
}void
find
(int a)
//字首和
for(
int i=head[a]
;i;i=g[i]
.last)
}node calc
(int o,
int l,
int r)
ll getans
(int o,
int l,
int r)
return ans;
}ll zans;
ll a,b,c;
intmain()
dfs_rmq(1
,0);
init_rmq()
; root=
0;son[0]
=m;totsze=n;
findroot(1
,0);
find
(root)
;while
(q--
)return0;
}
我們可以發現,乙個詢問點的答案為如下式子:(∑
i=1n
dis(
i))+
n×di
s(u)
−2×∑
i=1n
dis(
lca(
i,u)
)(i=
1∑n
dis(
i))+
n×di
s(u)
−2×i
=1∑n
dis
(lca
(i,u
))其中dis(
i)di
s(i)
表示ii
到根節點的距離。
這個式子和動態點分治中維護的資訊是十分類似的,我們開始先加上所有點到根的距離,然後對於一部分點v
v,它必須走v→l
ca→u
v→lc
a→u這條路,所以還有根節點回來的路徑為n×d
is(u
)n×d
is(u
),但是這樣無疑會多算一些邊,所以我們利用差分的思想,一條路影響是不會超過lca
lca的上方,所以我們減去lca
lca到根的距離,由於一條路是兩個點,所以減兩次,那麼便是答案了。
對於資訊的維護,我們用線段樹+樹鏈剖分即可,但是有點權l∼r
l∼r的限制,所以我們用主席樹即可做到維護,log
2nlo
g2n的查詢。
但是此題空間限制較小(對於主席樹來說),所以我們使用標記永久化,減少新的節點的開銷。
下面上**的連線我沒有打主席樹的**,所以借用的他人的
【in-luogu】
複雜度o(n
+nlo
g2n+
mlog
2n)o
(n+n
log2
n+ml
og2n
),常數較為小一點(因為沒有使用過多的stl
stl)。
HNOI2015實驗比較 題解
記得幾個月前自己曾經做過一道關於一張dag求排列的問題,現如今遇到了的是一道關於樹求排列的問題.這乙個問題看似簡單實際上有乙個細節那就是他可以取 這就使得複雜度公升高了.首先,最簡單的插孔原理。這乙個非常簡單,做這道題時,蒟蒻我現推式子。為什麼要解決這個問題呢,因為最基本的,在不考慮等於的情況下,n...
HNOI2015 菜餚製作 題解
傳送門 hnoi2015 菜餚製作 根據題目的描述,我們要做的首先是一步一步的分析 這個題肯定是拓撲排序無疑,因為要求的是滿足固定條件 有向圖的連邊 的某種排列,而難點就在於如何拓撲排序。根據題目的描述,我們首先想到的是根據字典序大小進行排序,那麼我們就舉例幾組資料來驗證一下是否正確,那麼先看下面這...
HNOI2015 接水果 題解
hnoi2015 接水果 給你乙個樹上路徑集合 s 每條路徑有個權值。每次詢問一條路徑 x,y 問它在 s 中包含的路徑中權值第 k 小的是多少。首先考慮如何判斷判斷一條路徑是否被另一條路徑包含。當一條路徑 x,y dep x dep y 是一條深度從淺到深的鏈時,路徑 u,v dep u dep ...