本文旨在對 oneindark 的做法進行記錄,jzm yyds!
設 \(f_x\) 表示 \(x\) 子樹外面已經有被選擇的節點的時候讓所有子樹內部的權值被區分開的最小代價
如果 \(x\) 有多個兒子,那麼最多只有乙個兒子的子樹中可以不放置任何標記點,那麼據此得到
\[f_x=\left(\sum_ \max(1,f_y)\right)-\left[0=\prod_ dp_y\right]
\]注意在 \(x\) 是時,只有 \(x\) 度數超過 \(2\) 才能直接使用 \(f_x\) 回答詢問
由於要加邊刪邊,只能使用 \(\rm lct\) 上 動態 \(\rm dp\) 的方式來維護
考慮 \(f_x\) 可以寫作乙個關於 \(x\) 的重兒子的分段函式:如果 \(f_=0\) 那麼就是輕兒子權值對 \(1\) 取 \(\max\) 之後的和(記作 \(sum_x\),另計輕兒子中權值為 \(0\) 的點的數量是 \(img_x\)),否則還要減掉是不是存在輕兒子 \(f\) 值為 \(0\)
由於後面都是可以維護的常量,在每個節點維護 \((z=sum_x,b=sum_x-img_x)\) 分別表示 \(f_=0\) 時得到 \(f_x=z\) 否則當前點 \(f_x=b+f_\)
這個分段函式的值域是定義域的子集,那麼可以函式復合,函式復合是有結合律的,在 \(\rm lct\) 上做push_up
也是合法的
但是函式復合不等於迭代復合反函式,而出於make_root
的需求,我們還需要維護上述函式復合的反方向過程,即 \(f_(f_(f_(x)))\) 翻轉的時候交換即可
回答詢問時考慮找乙個三度點makeroot
,把其所在的splay
的鏈底的權值傳到這棵樹剩下的點的復合函式結果求值即可
實現時注意access
將輕邊改成重邊之前要把兒子轉到根,因為計算貢獻時樹的結構發生了變化
code display
const int n=5e5+10;
struct func
func(int bb,int zz)
inline int get_val(int x)
}lef[n],rig[n];
int ls[n],rs[n],fa[n],stk[n],top,n,rev[n],sum[n],img[n];
inline func merge(func a,func b)
inline void push_up(int x)
if(rs[x])
return ;
}inline int isroot(int x)
inline void rotate(int x)
inline void push_rev(int p)
inline void push_down(int p) return ;
}inline void splay(int x,int tar=0)
if(!isroot(y)) rotate(((ls[z]==y)^(ls[y]==x))?x:y);
rotate(x);
} return ;
}inline int f_img(int x)
inline int calc(int x,int fat=0)
inline void obtain(int x,int y)
inline void lost(int x,int y)
inline void access(int x) return ;
}inline void make_root(int x)
inline void cut(int x,int y)else
return ;
}inline void link(int x,int y)
int deg[n];
set> st;
inline int get_ans()
inline void erase(int x)
inline void ins(int x)
signed main()
return 0;
}
注意到點的度數不超過 \(3\),那麼最小割也一定不超過 \(3\),對每個聯通塊分開討論:
code display
const int n=1e6+10;
mt19937_64 rand((unsigned)time(0));
ull val[n],ehs[n];
int dfn[n],low[n],tim,n,m;
vectornds[n];
int stk[n],top,dcc;
int bel[n],num,sum,ans;
vectorg[n],now;
inline void tarjan(int x,int fat)
if(low[x]==dfn[x])while(stk[top--]!=x);
sum+=nds[dcc].size()*(nds[dcc].size()-1)/2;
} return ;
}bool pas[n];
inline void get_nodes(int x)
int root,dep[n];
inline void dfs(int x,int fat)else
} return ;
}inline void push_xor(int x,int fat) return ;
}signed main()
for(int x=1;x<=n;++x) if(!pas[x])
ee[ehs[t]].push_back(t);
}for(auto &hs:ee)
} print(ans);
return 0;
}
根據樹上鄰域理論不難發現 \(|s|\ge 4\) 的時候必然無解,也可以理解為直徑端點個數超過 \(2\) 時每個點選擇方式不止 \(1\) 個
先特判掉 \(n=1\) 的情況
如果 \(|s|=1\) 構造乙個菊花來應付全是 \(-1\) 的 case
如果 \(|s|=2\),分是不是有 \(-1\) 來討論:
\(|s|=3\) 時,一定是 \(x,y,-1\),和上面的方法完全一樣,只不過中間夾了菊花 \(-1\)
code display
const int n=1e6+10;
int p[n],n;
setdiff;
inline void imp()
vector>edge;
inline void output()
signed main()
if(diff.size()==1)
if(diff.size()>3) imp();
if(diff.size()==2)
else
output();
exit(0);
}seta,b;
int a=*diff.begin(),b=*prev(diff.end());
rep(i,1,n) if(p[i]==a) a.insert(i); else b.insert(i);
if(!a.count(b)||!b.count(a)) imp();
int lsa=b,lsb=a; a.erase(b); b.erase(a);
while(a.size()&&b.size())
edge.emplace_back(lsa,lsb);
if(a.size())
if(b.size())
output();
}if((*diff.begin())!=-1) imp();
int a=*prev(diff.end()),b=*prev(prev(diff.end()));
if(p[a]!=b||p[b]!=a) imp();
seta,b,neg;
rep(i,1,n)
if(b.size()==1)
int lsa=b,lsb=a; b.erase(a); a.erase(b);
while(a.size()&&b.size())
if(edge.size()<=2&&(a.size()||b.size())) imp();
int cen=*neg.begin(); neg.erase(cen);
edge.emplace_back(cen,lsb);
edge.emplace_back(cen,lsa);
for(auto t:neg) edge.emplace_back(t,cen);
if(a.size()) for(auto t:a) edge.emplace_back(lsa,t);
if(b.size()) for(auto t:b) edge.emplace_back(lsb,t);
output();
return 0;
}
2022 02 23 學習筆記
編譯型效率高,但不能實時的獲取原始檔修改資訊,解釋型效率低,但可以實時獲取原始檔的修改 j a檔案執行時,會有預編譯過程,產生位元組碼檔案,然後在jvm中進行一系列過程,解釋到作業系統平台,所以j a既有編譯型也有解釋型,隨著當前硬體的不斷發展,這兩者的界限也逐漸模糊 當前啟用版本 2021.1.3...
考試總結 CQOI2017 考試總結
再奮鬥一年,爭取ak noip2016 cqoi2017 這是去年我立的flag。看考場,電腦挺快,而且配置和評測機一樣,可以放心的在自己的電腦上卡常測試啦,好評。碼了一道fft的題,沒網只好拷著回家交,鍵盤蜜汁小,enter佔據了兩行,旁邊還有關機按鈕。座位安排奧妙重重,和巴蜀dyf大神坐在一起。...
MBA考試總結
終於考完了 mba入學統考,兩年來參加了兩次,感覺還是挺辛苦和有壓力的。第一年沒有通過是因為之前了解太遲,大概準備了 20天左右,最後還是功成垂敗。09年其實也一直沒有心情複習的,逼到最後的 20天,狠了一把勁,還是狠狠的複習了幾天,貌似今年應該可以通過了。總結經驗如下 1 如果你決定去做一件事,請...