なぜ私はすべての木に木が癌になってきたベースリングに素朴な疑問を感じています......
ソリューション[IOI2008]島
タイトル効果:指定されたリングの森の木々、求めていると各ツリー径
ダイナミックプログラミング - DPツリー、モノトーンキュー、木リング
分析:
まず、「環」問題SBを削除する場合
我々\(F [U] \)で表される\(U \)最長鎖サブツリーのルートと、仮定エッジ\(E \)
\(F [U] = maxの\ {F [e.to] + e.dist \} \)
(ANS [U] \)\で表される(U \)\直径サブツリーのルートと
\(ANS [U] = maxの\ {ANS [e.to]、F '[U] + F [e.to] + e.dist \} \)
ツリー2つの可能な直径があり、その部分木の直径とそれによる根の直径は、サブツリー\(ANS \)転送が説明されていない、\(F「\)は、更新前の代表\(F \) 、我々は使用しますサブツリーの最長鎖プラス最長鎖の現在のサブツリー前に、第2ケースとなっています
ツリー\(DP \)することができます\(O(n)は\)解決するために
リングの直径がなく、リング直径介して、ツリーベースリング二つの直径、
私たちがポイントのリング上のリングの直径がなければ(ANS \)\検索で(最大\)\へ
我々はリングの直径を通って尋ねる場合と仮定される\(Uは、V \)明らかに、リング内にある\(ANS =最大\ {F [U] + F [V] + DIS(U、V)\} \) 、前記\(DIS(U、V) \) リングピース2.2より長いパスに
このようなものは暴力であれば(O(N ^ 3)\ \) 、プラスプレフィックスと行うことができます(O(N ^ 2)\ \)
二つの方向を取って以来、私たちは、チェーンリングに侵入していません
\(ANS =最大\ {F [U] + F [V] + SUM [U] -sum [V] \ \ Vクワッド<U \} \) 、我々は、得られる環プレフィックスから持って\(SUM \) 、そしてこの事は、単調なキューを最適化するために使用することができます\(O(n)は、\)
ウォータールーXueyibujingは形而上学の原因となった(:\バグ)\
\(0 \)より負より
問題:使用\(ベクトル\)生じ、\(vector.size()\)の戻り値\(サイズ\ _t \)は、タイプに統一され、次いで、符号なし整数、符号付きおよび符号なしの動作の数であります符号なしOP ......符号なしの負の番号が格納されます(GG \)\
\(トリック:\)被験者はそれぞれの度合いことを確実にするために指摘する(1 \)\我々が構築した場合、抗マップは外向的な木であります
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1e6 + 100;
typedef long long ll;
inline int read(){
int x = 0;char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))x = x * 10 + c - '0',c = getchar();
return x;
}
struct Edge{int to,dist;};
vector<Edge> G[maxn],rG[maxn];
vector<int> cir[maxn];
int deg[maxn],vis[maxn],iscir[maxn],q[maxn << 1],head,tail,n,cir_tot;
ll f[maxn],ans[maxn],sum[maxn << 1],val[maxn << 1],ansout;
inline void dfs(int u){
for(auto e : G[u]){
if(iscir[e.to])continue;
dfs(e.to);
ans[u] = max(ans[u],f[u] + f[e.to] + e.dist);
ans[u] = max(ans[u],ans[e.to]);
f[u] = max(f[u],f[e.to] + e.dist);
}
}
inline void topo(){
queue<int> Q;
for(int i = 1;i <= n;i++){
iscir[i] = 1;
if(!deg[i])Q.push(i);
}
while(!Q.empty()){
int u = Q.front();Q.pop();
iscir[u] = 0;
for(auto e : rG[u])
if(!--deg[e.to])Q.push(e.to);
}
for(int i = 1;i <= n;i++)
if(iscir[i] && !vis[i]){
int now = i;cir_tot++;
do{
for(auto e : G[now])
if(iscir[e.to]){
cir[cir_tot].push_back(e.to);
vis[now = e.to] = 1;break;
}
}while(now != i);
}
}
inline void solve(){
for(int id = 1;id <= cir_tot;id++){
reverse(cir[id].begin(),cir[id].end());
ll tmp = 0;
for(int x : cir[id])
dfs(x),tmp = max(tmp,ans[x]);
for(int i = 0;i < cir[id].size();i++){
int u = cir[id][i],pre = i == 0 ? cir[id][cir[id].size() - 1] : cir[id][i - 1];
for(auto e : G[u])
if(e.to == pre){sum[i] = sum[i + cir[id].size()] = e.dist;break;}
}
for(int i = 1;i < cir[id].size() * 2;i++)
sum[i] += sum[i - 1];
for(int i = 0;i < cir[id].size() * 2;i++)
val[i] = f[cir[id][i % cir[id].size()]] - sum[i];
q[head = tail = 1] = 0;
for(int i = 1;i < cir[id].size() * 2;i++){
while(head <= tail && q[head] <= (i - (int)cir[id].size()))head++;
if(head <= tail)tmp = max(tmp,f[cir[id][i % cir[id].size()]] + sum[i] + val[q[head]]);
while(head <= tail && val[q[tail]] <= val[i])tail--;
q[++tail] = i;
}
ansout += tmp;
}
}
inline void addedge(int from,int to,int dist){
G[from].push_back(Edge{to,dist});
deg[from]++;
rG[to].push_back(Edge{from,0});
}
int main(){
n = read();
for(int u,v = 1;v <= n;v++)
u = read(),deg[u]++,G[u].push_back(Edge{v,read()}),rG[v].push_back(Edge{u,0});
topo();
solve();
printf("%lld\n",ansout);
return 0;
}