思路:
考慮按照 dfn 序將關鍵點的集合排序後為 \(a_0,a_1,\cdots,a_k\),則答案為:
\[\frac{\sum\limits_{i=0}^k \operatorname{dis}(a_i,a_{(i+1) \bmod k})}{2}
\]
簡單證明一下:
需要找出包含一些關鍵點的最小聯通匯出子圖。
則隨便以一個關鍵點為根,對於子樹內沒有關鍵點的子樹直接丟掉,就形成了新樹;新樹的葉子節點絕對都是關鍵點。
我們要找出新樹的邊集數量,即在 dfs 搜尋的時候,每條邊會在搜入子樹時經過一次,出子樹的時候經過一次,總計每條邊會經過兩次。
這個 dfs 搜尋的過程等價於按照葉子節點 dfn 序的相鄰取距離。
故我們需要動態維護上面那個式子的答案,注意到每次我們只刪除或插入一個數,直接使用 set
維護即可。
如果你想,也自己寫平衡樹。
時間複雜度為 \(O(Q \log N)\)。
P10930 異象石 與 CF176E Archaeology Code:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
#define For(i,l,r) for(int i=l;i<=r;i++)
#define _For(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const ll N=1e5+10;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
inline char get(){
char c;
while(1){
c=getchar();
if(c=='+'||c=='-'||c=='?')
break;
}
return c;
}
char op;
ll n,m,u,v,w,x,ans,cnt;
ll dfn[N];
set<pi> S;
vector<pi> E[N];
void add(ll u,ll v,ll w){
E[u].push_back({v,w});
E[v].push_back({u,w});
}
void dfs(ll u,ll fa){
dfn[u]=++cnt;
for(auto t:E[u]){
ll v=t.fi;
if(v==fa)
continue;
dfs(v,u);
}
}
namespace Tree{
ll siz[N],z[N],fa[N],t[N],d[N],dep[N];
void dfs1(ll u,ll f){
siz[u]=1;
for(auto t:E[u]){
ll v=t.fi,w=t.se;
if(v==f)
continue;
fa[v]=u;
d[v]=d[u]+w;
dep[v]=dep[u]+1;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[z[u]])
z[u]=v;
}
}
void dfs2(ll u,ll k){
t[u]=k;
if(!z[u])
return ;
dfs2(z[u],k);
for(auto t:E[u]){
ll v=t.fi;
if(v==fa[u]||v==z[u])
continue;
dfs2(v,v);
}
}
ll Lca(ll u,ll v){
while(t[u]!=t[v]){
if(dep[t[u]]<dep[t[v]])
swap(u,v);
u=fa[t[u]];
}
return dep[u]<dep[v]?u:v;
}
ll dis(ll u,ll v){
return d[u]+d[v]-2ll*d[Lca(u,v)];
}
void init(){
dfs1(1,1);
dfs2(1,1);
}
};
void insert(ll x){
if(S.empty()){
S.insert({dfn[x],x});
return ;
}
set<pi>::iterator a,b;
b=S.upper_bound({dfn[x],x});
if(b==S.end()){
a=b,a--;
ans-=Tree::dis((*S.begin()).se,(*a).se);
ans+=Tree::dis((*S.begin()).se,x);
ans+=Tree::dis((*a).se,x);
}
else if(b==S.begin()){
a=S.end(),a--;
ans-=Tree::dis((*b).se,(*a).se);
ans+=Tree::dis(x,(*a).se);
ans+=Tree::dis(x,(*b).se);
}
else{
a=b,a--;
ans-=Tree::dis((*a).se,(*b).se);
ans+=Tree::dis(x,(*a).se);
ans+=Tree::dis(x,(*b).se);
}
S.insert({dfn[x],x});
}
void del(ll x){
if(S.size()==1){
S.erase({dfn[x],x});
return ;
}
set<pi>::iterator a,b,c,d=S.end();
a=b=c=S.find({dfn[x],x});
a--,d--,c++;
if(c!=S.end())
ans-=Tree::dis((*c).se,(*b).se);
if(b!=S.begin())
ans-=Tree::dis((*a).se,(*b).se);
if(c!=S.end()&&b!=S.begin())
ans+=Tree::dis((*a).se,(*c).se);
if(b==S.begin()){
ans-=Tree::dis((*b).se,(*d).se);
ans+=Tree::dis((*c).se,(*d).se);
}
if(c==S.end()){
ans-=Tree::dis((*b).se,(*S.begin()).se);
ans+=Tree::dis((*a).se,(*S.begin()).se);
}
S.erase(b);
}
int main(){
n=read();
For(i,1,n-1){
u=read(),v=read(),w=read();
add(u,v,w);
}
dfs(1,1);
Tree::init();
m=read();
while(m--){
op=get();
if(op=='+'){
x=read();
insert(x);
}
else if(op=='-'){
x=read();
del(x);
}
else{
write(ans>>1);
putchar('\n');
}
//cerr<<(ans>>1)<<'\n';
// cerr<<"Yes";
}
return 0;
}
P3320 [SDOI2015] 尋寶遊戲 Code:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
#define For(i,l,r) for(int i=l;i<=r;i++)
#define _For(i,l,r) for(int i=r;i>=l;i--)
using namespace std;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const ll N=1e5+10;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
inline char get(){
char c;
while(1){
c=getchar();
if(c=='+'||c=='-'||c=='?')
break;
}
return c;
}
char op;
ll n,m,u,v,w,x,ans,cnt;
ll dfn[N];
set<pi> S;
vector<pi> E[N];
bool f[N];
void add(ll u,ll v,ll w){
E[u].push_back({v,w});
E[v].push_back({u,w});
}
void dfs(ll u,ll fa){
dfn[u]=++cnt;
for(auto t:E[u]){
ll v=t.fi;
if(v==fa)
continue;
dfs(v,u);
}
}
namespace Tree{
ll siz[N],z[N],fa[N],t[N],d[N],dep[N];
void dfs1(ll u,ll f){
siz[u]=1;
for(auto t:E[u]){
ll v=t.fi,w=t.se;
if(v==f)
continue;
fa[v]=u;
d[v]=d[u]+w;
dep[v]=dep[u]+1;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[z[u]])
z[u]=v;
}
}
void dfs2(ll u,ll k){
t[u]=k;
if(!z[u])
return ;
dfs2(z[u],k);
for(auto t:E[u]){
ll v=t.fi;
if(v==fa[u]||v==z[u])
continue;
dfs2(v,v);
}
}
ll Lca(ll u,ll v){
while(t[u]!=t[v]){
if(dep[t[u]]<dep[t[v]])
swap(u,v);
u=fa[t[u]];
}
return dep[u]<dep[v]?u:v;
}
ll dis(ll u,ll v){
return d[u]+d[v]-2ll*d[Lca(u,v)];
}
void init(){
dfs1(1,1);
dfs2(1,1);
}
};
void insert(ll x){
if(S.empty()){
S.insert({dfn[x],x});
return ;
}
set<pi>::iterator a,b;
b=S.upper_bound({dfn[x],x});
if(b==S.end()){
a=b,a--;
ans-=Tree::dis((*S.begin()).se,(*a).se);
ans+=Tree::dis((*S.begin()).se,x);
ans+=Tree::dis((*a).se,x);
}
else if(b==S.begin()){
a=S.end(),a--;
ans-=Tree::dis((*b).se,(*a).se);
ans+=Tree::dis(x,(*a).se);
ans+=Tree::dis(x,(*b).se);
}
else{
a=b,a--;
ans-=Tree::dis((*a).se,(*b).se);
ans+=Tree::dis(x,(*a).se);
ans+=Tree::dis(x,(*b).se);
}
S.insert({dfn[x],x});
}
void del(ll x){
if(S.size()==1){
S.erase({dfn[x],x});
return ;
}
set<pi>::iterator a,b,c,d=S.end();
a=b=c=S.find({dfn[x],x});
a--,d--,c++;
if(c!=S.end())
ans-=Tree::dis((*c).se,(*b).se);
if(b!=S.begin())
ans-=Tree::dis((*a).se,(*b).se);
if(c!=S.end()&&b!=S.begin())
ans+=Tree::dis((*a).se,(*c).se);
if(b==S.begin()){
ans-=Tree::dis((*b).se,(*d).se);
ans+=Tree::dis((*c).se,(*d).se);
}
if(c==S.end()){
ans-=Tree::dis((*b).se,(*S.begin()).se);
ans+=Tree::dis((*a).se,(*S.begin()).se);
}
S.erase(b);
}
int main(){
n=read(),m=read();
For(i,1,n-1){
u=read(),v=read(),w=read();
add(u,v,w);
}
dfs(1,1);
Tree::init();
while(m--){
x=read();
if(f[x])
del(x);
else
insert(x);
f[x]^=1ll;
write(ans);
putchar('\n');
}
return 0;
}