經常發現一些布布扣一類的**直接爬csdn的blog,娘的
對於樹上的路徑問題,一種高效的處理方式就是分治演算法。關於樹分治演算法的研究,詳見2023年ioi國家集訓隊**——《分治演算法在樹的路徑問題中的應用》。**裡第一道例題通常對於樹上的分治演算法有兩種,第一種是針對點進行的分治,另一種是針對邊進行的分治,可以證明,大部分情況下點分治演算法的效能更加穩定,而邊分治在某些情況下,演算法效率非常低。所以以下主要討論點分治。
如poj-1741,求解一棵樹中路徑長度不大於k的有多少點對。
對於一棵有根樹,樹中滿足對所對應的一條路徑,必然是以下兩種情況之一:
1.經過根節點
2.路徑在以根節點某個兒子為根的一棵子樹中
對於情況2,可以遞迴求解,下面主要來考慮情況1.
那麼對於這道題的情況1,設dis[i]為節點i到根的距離,我們就是要求解有多少對經過根的路徑,那麼問題等價於能找到多少對不同的點對(i,j),使得dis[i]+dis[j]<=k,而且i和j要屬於以當前根的兩個不同的兒子為根的子樹中。
將問題轉化以下,就可以發現所求結果等價於在一棵有根樹中找到的點對數x-在以當前根的兒子為根的子樹所找到的點對數。
求x、y的過程均可以轉化為以下問題:已知a[1],a[2],…a[m],求滿足i
參考了網上的兩個板
kuangbin的solve寫的很csy,這一部分用了這個
#include
#include
#include
#include
using
namespace
std;
const
int n = 1e4 + 7;
const
int inf = 0x3f3f3f3f;
int n, k, ans;
struct edge
edge (int f, int t, int _w, int n):from(f),to(t),w(_w),nxt(n){}
} edges[n * 2];
bool vis[n];
int head[n], e, siz[n], dep[n];
void init()
void addedge(int u,int v,int w)
int dfssize(int u, int pre)
return siz[u];
}//找重心
void dfsroot(int u, int pre, int totnum, int &minn, int &root)
if(maxx < minn)
}//求每個點離重心的距離
void dfsdep(int u,int pre,int dist, int &num)
}//計算以u為根的子樹中有多少點對的距離小於等於k
int calc(int u, int d)
void solve(int u)
}int main()
ans = 0;
solve(1);
printf("%d\n", ans);
}return
0;}
現場的時候k = 7,樹形dp可以水過,重現賽的時候k改為了10
需要樹分治,裸的樹分治(如上),統計距離小於等於k的點對數
本題問路徑經包含所有顏色的點對數
利用位運算狀壓,k種顏色,k<=10,每種顏色佔一位
原題轉化為統計路徑 or運算和 == fullk的點對數
fullk =(1<
poj1741通過乙個sort和兩個指標統計出了dist<=k的點對數
這裡是二進位制位,sort不靈了,需要另一種nlogn的方案
對於每點u的狀態dep[u],列舉其每個子集s0,ans += hash[fullk ^ so]
列舉子集一開始也不會,很玄學,這裡有一些講解,騷到了
位運算狀壓其實很好想,把原來的加號改成or運算就好了
很騷的一段就是calc中的一段,從這裡再次盜個圖來,舉了個列舉子集的例子
我見他**第一行是
/**此**借鑑了某大神的,我看懂了後又分析的*/
似乎他也參考了這個blog
扯了一堆有的沒的
最後貼自己的**吧,用上題的板子改,dfsdep和dfs看著改就好,calc動些腦子
#include
#include
#include
#include
#include
using
namespace
std;
typedef
long
long ll;
const
int n = 5e4 + 7;
const
int inf = 0x3f3f3f3f;
int n, k;
ll ans;
int col[n], fullk;
ll hashs[1200];
struct edge
edge (int f, int t, int _w, int n):from(f),to(t),w(_w),nxt(n){}
} edges[n * 2];
bool vis[n];
//本題中邊無w,dep為節點到root col or運算和
int head[n], e, siz[n], dep[n];
void init()
void addedge(int u,int v,int w)
int dfssize(int u, int pre)
return siz[u];
}//找重心
void dfsroot(int u, int pre, int totnum, int &minn, int &root)
if(maxx < minn)
}//求每個點離重心的距離
void dfsdep(int u, int pre, int dist, int &num)
hashs[dep[i]]++;
}return ans;
}void dfs(int u)
}int main()
for (int i = 1; i < n; i++)
ans = 0;
if (k == 1) ans = (ll)n * (ll)n;
else dfs(1);
printf("%lld\n", ans);
}return
0;}
poj2531,給個20個點的圖,問最小割
還有點迷糊這個怎麼就能剪枝了
#include
#include
using
namespace
std;
int main()
這題正解好像是dfs
不過,隨機化亂搞似乎也可以,亂搞好玩啊,here
操作1e5次
對於每一次操作,隨機選擇乙個點,把他放到另乙個集合裡面去,然後for一遍,算出當前的割值sum,再與記錄的最大值ans比較更新
#include
#include
#include
#include
using
namespace
std;
int n, g[22][22];
bool go[22];
int main()
ans = max(sum, ans);
}printf("%d\n", ans);
}return
0;}
樹分治入門 POJ1741,hdu5977
經常發現一些布布扣一類的 直接爬csdn的blog,娘的 對於樹上的路徑問題,一種高效的處理方式就是分治演算法。關於樹分治演算法的研究,詳見2009年ioi國家集訓隊 分治演算法在樹的路徑問題中的應用 通常對於樹上的分治演算法有兩種,第一種是針對點進行的分治,另一種是針對邊進行的分治,可以證明,大部...
POJ 1741 樹分治入門
include include include include using namespace std const int inf 0x3f3f3f3f const int max 1e4 5 點分治 cursize 樹當前大小 curroot 當前樹的根 son i 節點i的子節點的個數 d i ...
POJ 1741 樹的分治
題意就是求樹上距離小於等於k的點對有多少個 n2的演算法肯定不行,因為1w個點 這就需要分治。可以看09年漆子超的 本題用到的是關於點的分治。乙個重要的問題是,為了防止退化,所以每次都要找到樹的重心然後分治下去,所謂重心,就是刪掉此結點後,剩下的結點最多的樹結點個數最小。每次分治,我們首先算出重心,...