hdu5293 lca dp 樹狀陣列 時間戳

2022-05-15 04:20:42 字數 1861 閱讀 3982

題意是給了 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 #include 

#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;

}

view code

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 ...