題意是給了 n 個點的樹,會有m條鏈條 鏈結兩個點,計算出他們沒有公共點的最大價值, 公共點時這樣計算的只要在他們 lca 這條鏈上有公共點的就說明他們相交
dp[i]為這個點包含的子樹所能得到的最大價值
sum[i]表示這個點沒有選擇經過i這個點鏈條的總價值
兩種選擇
這個點沒有被選擇
dp[i]=sum[i]=sigma(dp[k])k為i的子樹
選擇了某個鏈
假設這條鏈 為(tyuijk)
那麼dp[i]=(sum[i]-dp[u]-dp[j])+(sum[j]-dp[k])+dp[k] +(sum[u]-dp[y])+(sum[y]-dp[t])+sum[t];
整理後發現 dp[i]=sum[i] +(sum[j]-dp[j])+(sum[k]-dp[k])+(sum[u]-dp[u])+(sum[y]-dp[y])+(sum[t]-dp[t]);
使用lca計算出每條鏈的最近公共祖先,在這個最近公共祖先上判斷是否使用這條鏈,還有我們可以使用時間戳加樹狀陣列來求得sum和dp
#include #includeview code#include
#include
#include
using
namespace
std;
const
int maxn=100000+10
;int to[maxn*2],nx[maxn*2],h[maxn*2
],numofedg,timoflook;
int fa[maxn][20
],first[maxn],last[maxn],depth[maxn];
void addedg(int u, int
v)void dfs(int cur, int per, int
dep)
for(int i=h[cur]; i; i=nx[i])
last[cur]=++timoflook;
}int getlca(int u,int
v)
for(int i=19; i>=0; i--)
}return fa[u][0];}
struct
edgp[maxn];
vector
e[maxn];
int dp[maxn],sum[maxn],cs[maxn*3],cd[maxn*3
];int lowbit(int
x)void add(int x, int d, int *c)
}int getsum(int x, int *c)
return
ret;
}void solve(int cur, int
per)
dp[cur]=sum[cur];
for(int i=0; i)
add(first[cur],sum[cur],cs);
add(last[cur],-sum[cur],cs);
add(first[cur],dp[cur],cd);
add(last[cur],-dp[cur],cd);
}int
main()
for(int i=1; i)
fa[1][0]=1
; dfs(
1,1,0
);
for(int i=0; i)
solve(
1,-1
); printf(
"%d\n
",dp[1
]); }
return0;
}
hdu 3887 樹狀陣列
給你一棵樹,每個節點都有個編號。讓你求乙個節點他的子樹中編號比他小的節點有幾個。編號唯一,從1 n,已給出根節點 解 樹狀陣列統計。轉化為線性序列。可以想到的是,若要統計乙個節點,那麼比它小的孩子必須先插完,然後統計就行了。對於乙個節點i來說,只要把所有x那麼對於所有節點來說也是這樣的,從一開始插,...
hdu 3333 樹狀陣列
此題與3743相仿,但本題資料較大,需要用到離散化。如何去掉重複元素呢?採用離線演算法 首先將詢問按右端點從小到大排序,離線處理時,記錄每個元素所在位置,遇到重複元素時,從它之前出現的位置減去這個元素,這樣就是的每個元素總是出現在最後。include include include include ...
樹狀陣列 HDU1166
繼續上次那題,我們現在採用樹狀陣列來解。樹狀陣列主要用來進行區間求和統計和定點更新操作,樹狀陣列的儲存是如下方式的 假設陣列a為a 1 a 2 a 3 a n 現在我們另陣列c 1 a 1 c 2 a 1 a 2 c 3 a 3 c 4 a 1 a 2 a 3 a 4 這是啥結構呢?其實c i a ...