1. 程式人生 > >分治入門——樹分治

分治入門——樹分治

分治思想:劃分子問題,解決子問題,合併子問題

題目:POJ1741
題意:給定一棵含有n個節點的無向帶權樹,滿足距離≤k的兩點共有多少對?(n≤1e4)

題解:
(1)首先找到樹A的重心,(重心指的是一個節點,將該節點刪去之後剩下的最大子樹的節點數最小)將其作為樹A的根。在數列的分治之中我們是直接去區間的中間為分界線,但是這裡,如果隨意將某個點刪去,最壞的情況可能是這棵樹退化成一條鏈,遞迴的深度變成了O(n)。而將重心刪去後,剩餘子樹中的最大子樹大小≤n/2(必然),遞迴深度為O(logn)。

(2)找到樹A重心為根節點之後,將其劃分為以兒子為根的眾多子樹,再新增一個只有一個節點子樹,該節點直接連線根節點且邊權為0。計算滿足答案且經過根節點的(i,j)的對數(前面新增的單節點子樹就是計算根節點到其餘節點的答案)累加到ans。但是這裡面得到的答案包含了來自同一棵子樹的(i,j),因為他們經過了根節點的路徑並不是最短路,而在後續的子問題解決中還會計算到,因此在這裡需要減去來自同一棵子樹的(i,j)的答案數。

(3)將根節點刪去之後,分治解決子樹相同問題

原始碼如下

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define pb push_back

using namespace std;
const int maxn = 10005, inf = 0x3f3f3f3f;

struct Edge
{
	int to, next, dist;
}edge[maxn<<1];
int head[maxn], cnt;

void addedge(int u, int v, int w)
{
	edge[cnt].to = v;
	edge[cnt].dist = w;
	edge[cnt].next = head[u];
	head[u] = cnt++;
}

int n, k, ans;
int num[maxn];//num[i]表示以i為根的樹 的節點數
int dp[maxn];//一維滾動。dp[i]將i刪去後 當前樹的最大聯通塊的大小

int Stack[maxn], top1;//棧
bool vis[maxn] ;//true表刪除
int size;//當前樹的節點數
int root;//根節點

void get_root(int u, int fa)//深搜遍歷的同時找尋樹的重心root
{
	dp[u] = 0;
	num[u] = 1;//初始化

	for(int i = head[u]; ~i; i  = edge[i].next)
	{
		int v = edge[i].to;
		if(v!=fa && !vis[v]	)
		{//保證不回溯
			get_root(v, u);
			num[u] += num[v];//加上兒子的節點數就是根的節點數
			dp[u] = max(num[v], dp[u]);//最大聯通塊大小可能是子樹大小
		}
	}
	//最大聯通塊還有可能是當前樹刪除子樹u之後的樹大小
	dp[u] = max(dp[u] , size - num[u]);
	//最後跟目前的重心對比
	if(dp[u]<dp[root])	root = u;
}

int dist[maxn];//到根節點的距離
inline bool cmp(int i, int j)
{
	return dist[i] < dist[j];
}

void Find_dist(int u, int fa , int d)
{//計算當前樹的所有節點到根的距離,並將點入棧
	Stack[++top1] = u;
	dist[u] = d;
	for(int i = head[u]; ~i ; i = edge[i].next)
	{
		int v = edge[i].to;
		if(vis[v] || v==fa)	continue ;
		Find_dist(v, u, d+edge[i].dist);
	}
}

int calc(int l, int r)//計算滿足距離≤k的(i,j)個數
{
	int j = r, Ans = 0;//此時stack中l到r是按照dist升序排好的,ij一前一後往中間掃
	for(int i = l; i <= r; i ++)
	{
		while(dist[Stack[i]]+dist[Stack[j]]>k && j>i) j--;
		if(i==j)	break ;
		Ans += j-i;
		//Stack[i+1]~Stack[j]都是滿足條件的
	}
	return Ans;
}

void solve(int u, int fa)
{
	dp[0] = maxn;
	size = num[u];
	root = 0;
	
	get_root(u, fa);//找到重心並將之轉換為當前樹的根

	top1 = 0;
	int top2 = 0;
	for(int i = head[root]; ~i; i = edge[i].next)
	{
		int v = edge[i].to;
		if(vis[v])	continue;
		top2 = top1;
		Find_dist(v, root, edge[i].dist);
		//top2+1 到top1+1為子樹v的所有節點
		sort(Stack+top2+1, Stack+top1+1, cmp);
		ans -= calc(top2+1, top1);//減去在同一棵子樹且經過根節點(即非最短距離)的答案數
	}
	
	Stack[++top1] = root;
	dist[root ] = 0;
	sort(Stack+1, Stack+top1+1, cmp);
	ans += calc(1, top1);

	vis[root] = 1;

	for(int i = head[root]; ~i; i = edge[i].next)
		if(!vis[edge[i].to])
			solve(edge[i].to, root);//分治解決
}

void init()
{
	memset(head, -1, sizeof head);
	memset(vis, 0, sizeof vis);
	ans = 0;
	cnt = 0;
}

int main()
{
	while(scanf("%d %d", &n, &k), n&&k)
	{
		init();
		for(int i = 1; i < n; i ++)
		{
			int u, v, d;
			scanf("%d %d %d", &u, &v, &d);
			addedge(u, v, d);
			addedge(v, u, d);
		}
		num[1] = n;
		solve(1, 0);
		printf("%d\n", ans);
	}
    return 0;
}


相關推薦

分治入門——分治

分治思想:劃分子問題,解決子問題,合併子問題 題目:POJ1741 題意:給定一棵含有n個節點的無向帶權樹,滿足距離≤k的兩點共有多少對?(n≤1e4) 題解: (1)首先找到樹A的重心,(重心指的是一個節點,將該節點刪去之後剩下的最大子樹的節點數最小)將其作為

基於點分治分治

algorithm 計算 開始 tails 論文 continue dfsr size 多少 本文代碼來源:https://blog.csdn.net/yang_7_46/article/details/9966455 本文參考論文來源:https://wenku.baid

分治入門——平面分治

分治思想:劃分子問題,解決子問題,合併子問題 題目:UVA 10245 題意:在一個二維平面內給定n個點,求最近的兩個點的距離。(n≤10000) 題解:直接暴力列舉所有點是肯定行不通的。那麼基於分治的思想:按照橫座標排序後,分成兩個部分,那麼最近距離的點

分治入門:例題poj1741

ios targe www for define 算法分析 urn article details 題目鏈接:Tree 樹分治參考資料:09年漆子超 ZigZagK的博客 【點分治】的學習筆記和眾多例題 以上的資料是我看過好的,具體算法分析實現都講明白,貼一下我的代碼

poj1741+poj1987+poj2114——點分治入門題集合

剛才 是把 註意 幫我 legend 機房 ini ext one 最近看了看點分治,從poj上找到幾道題,都比較裸。而且感覺這三道題都長得差不多呀qwq ———————————————————————————————————————————————— 【poj 1741】

POJ 1741 男人八題——分治

tor pst def roo 容易 air sizeof ram 出發 Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 23829 Accepted

【bzoj1095】[ZJOI2007]Hide 捉迷藏 動態分治+堆

max 插入 fine 時間 結構 答案 += oot tdi 題目描述 捉迷藏 Jiajia和Wind是一對恩愛的夫妻,並且他們有很多孩子。某天,Jiajia、Wind和孩子們決定在家裏玩捉迷藏遊戲。他們的家很大且構造很奇特,由N個屋子和N-1條雙向走廊組成,這N-1條

HDU 6183 Color it cdq分治 + 線段 + 狀態壓縮

sample div cnblogs 分用 return cmp pac math for each Color it Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 132768/132768 K (J

【bzoj4012】[HNOI2015]開店 動態分治+二分查找

oot pri push_back amp data 很多 nbsp targe pac 題目描述 風見幽香有一個好朋友叫八雲紫,她們經常一起看星星看月亮從詩詞歌賦談到人生哲學。最近她們靈機一動,打算在幻想鄉開一家小店來做生意賺點錢。這樣的想法當然非常好啦,但是她們也發現

[BZOJ3295][Cqoi2011]動態逆序對 CDQ分治&

的確 分治 mat fda 應該 through tex 瓶頸 這樣的 3295: [Cqoi2011]動態逆序對 Time Limit: 10 Sec Memory Limit: 128 MB Description 對於序列A,它的逆序對數定義為滿足i&

【BZOJ4675】點對遊戲 分治+期望

三人 hellip 小數 tro 統計 int 多少 microsoft 題解 【BZOJ4675】點對遊戲 Description 桑尼、露娜和斯塔在玩點對遊戲,這個遊戲在一棵節點數為n的樹上進行。 桑尼、露娜和斯塔三人輪流從樹上所有未被占有的節點中選取一點,歸

【BZOJ3648】寢室管理 分治

數組 沒有 != 決定 算法 microsoft put ron 1+n 【BZOJ3648】寢室管理 Description T64有一個好朋友,叫T128。T128是寄宿生,並且最近被老師叫過去當宿管了。宿管可不是一件很好做的工作,碰巧T128有一個工作上的問題

cdq分治入門--BZOJ1176: [Balkan2007]Mokia

。。 入門 矩形 ++ bzoj == img != void 對w*w,w<=2000000的矩形,一開始全是0(或一開始全是s),n<=170000個操作,每次操作:矩陣內某點加上一個數,查某一個子矩陣的和,保證修改數<=160000,詢問數<=

【BZOJ4372】爍爍的遊戲 動態分治+線段

printf esp ans 當前 sam 註意 與他 dfs 接下來 【BZOJ4372】爍爍的遊戲 Description 背景:爍爍很喜歡爬樹,這嚇壞了樹上的皮皮鼠。題意:給定一顆n個節點的樹,邊權均為1,初始樹上沒有皮皮鼠。爍爍他每次會跳到一個節點u,把周圍

[poj] 1741 Tree || 分治

clas com 情況 oid logs algo return sca har 原題 求樹上距離不超過k的點對數。 樹分治的板子題。 每次把一棵樹由重心分為多顆樹,分別遞歸處理。 我們要求的就是不在同一個聯通塊中的符合答案的對數(在同一個的會通過遞歸轉化為不在同一個的)

POJ 1741 Tree | 分治

樹分治 等於 namespace poj edge i++ str static tree 求樹上距離小於等於K的點對對數 #include<cstdio> #include<algorithm> #include<cstring>

BZOJ 2152 聰聰可可 | 分治

static turn names += efi i++ class -- alc #include<cstdio> #include<algorithm> #include<cstring> #define N 20005 typed

bzoj 1758 [Wc2010]重建計劃 分數規劃+分治單調隊列check

href 整數 order font 城市 input ans ref pro [Wc2010]重建計劃 Time Limit: 40 Sec Memory Limit: 162 MBSubmit: 4345 Solved: 1054[Submit][Status][

【CF840D】Destiny 分治(線段)

def bool open != ostream for get cto 都在 【CF840D】Destiny 題意:給你一個長度為n的序列,q次詢問,每次指定l r k,求[l,r]中出現次數$>\frac {r-l+1} k$的所有數中最小的那個數。 $n,q

【學術篇】bzoj3262 陌上花開. cdq分治入門

spa pri 一點 markdown 思考 也會 關心 做了 升級 花兒們已經很累了—— 無論是花形、顏色、還是氣味, 都不是為了給人們擺出來欣賞的, 更不是為了當做出題的素材的, 她們並不想自己這些屬性被沒有生命的數字量化, 並不想和其它的花攀比, 並無意分出個三六九等