倍增與位運算有很多共性;這題做法有一點像「線段樹上二分」和「線段樹套二分」的關係。給出一棵n個點的樹(以1號點為根),定義dep[i]為點i到根路徑上點的個數。眾所周知,樹上最近公共祖先問題可以用倍增演算法解決。現在我們需要算出這個演算法精確的複雜度。我們定義計算點i和點j最近公共組先的精確複雜度為bit[dep[i]-dep[lca(i,j)]]+bit[dep[j]-dep[lca(i,j)]](bit[i]表示i在二進位制表示下有多少個1,lca(i,j)表示點i和點j的最近公共祖先)。為了計算平均所需的複雜度為多少,請你幫忙計算任意兩點計算最近公共組先所需複雜度的總和。
即計算 ∑n−1i=1∑nj=i+1
bit[dep[i]-dep[lca(i,j)]]+bit[dep[j]-dep[lca(i,j)]]
第一行乙個數n表示點數(1<=n<=100,000)接下來n-1行每行兩個數x,y表示一條邊(1<=x,y<=n)
乙個數表示答案
41 21 3
2 4
8題目已經良心地把要求的式子給出來了。
位運算計數題自然而然考慮按位計算貢獻,注意到要求的是bit即個數,也就是說高位和低位是同性的。而這題略有特殊的是在於可以與倍增相結合做一些有趣的事情。
由於邊權為1,倍增預處理的到祖先節點的二的冪次,就是到祖先節點的距離的二進位制拆分。
那麼就可以先列舉logn數量的每一種2^i深度d,再列舉所有n個點。對於每乙個列舉的點,統計與它相距2^
直觀來說就是這張圖。主要**是這樣的:
1如果想要更加程式化的描述,見for (int d=0; d<19; d++)
211 }
51nod1709 複雜度分析
這篇部落格。
1 #include2const
int maxn = 100035;3
4int
n,w[maxn];
5long
long
ans;
6int
chain[maxn],tot[maxn],chtot;
7int f[maxn][23
],dep[maxn],fa[maxn];
8int edgetot,edges[maxn<<1],nxt[maxn<<1
],head[maxn];910
intread()
1122
void addedge(int u, int
v)23
27void dfs(int x, int
fat)
2838}39
}40intmain()
4159
}60 printf("
%lld\n
",ans);
61return0;
62 }
在這裡給出一種o(nlog)的做法。記錄每個節點的fa和子樹size。【抽風沒法正常顯示數學公式我也很難受啊】列舉乙個k,用s[i]表示節點i子樹內和i距離小於 2^k 大於等於2^k−1的節點數,v[i]表示節點i子樹內和i距離小於 2^k 大於等於 2^k−1 的節點和i距離的bit總數,now[i]表示i向上的第 2^k−1 個祖先。
每次倍增計算每個點子樹內和它距離小於 2^k 大於等於 2^k−1 的點的距離對答案的貢獻即可。
@hzq84621 自
end
51nod 1709 複雜度分析
考慮樸素的暴力,相當於列舉u點的每個祖先f,然後統計一下這個點f除了某個兒子裡有u的那個子樹之外的節點個數,乘上f到u距離的二進位制1的個數 那麼我們用倍增來實現這個東西,每次列舉二進位制的最高位j,用dfs序列舉點u,找到u的距離為 2 j 的祖先,那麼在fa u j 這個祖先的位置,j這一位的出...
51Nod1709 複雜度分析
題目鏈結 一道很有意思的題。我們考慮按位累計貢獻。記錄 dp i j 為上一步倍增跳了 2 j 步,跳到了 i 點的所有狀態 1 的個數和。可以理解為,對於乙個兒子u和他的祖先v的深度差,可以表示為乙個二進位制數。我們倍增的將u跳到v,每次跳的長度一定比上次小,且一定是 2 k 對於乙個點i,上一步...
51nod 1389 跳跳樹 倍增
小a與小b在樹上玩乙個遊戲,每一輪遊戲小a與小b在樹上選兩個點,然後小a朝著小b所在的方向移動。神奇的是,這棵樹上每條邊都有乙個長度的,每個點上都有一棵非常高的松樹。小a可以從高處不耗費任何體力跳往相鄰的低處,也可以耗費一點體力,走不超過k的長度的路徑走到某個點然後跳到松樹頂端 不能停在路 現在他們...