[动态树分治]

最近学习了一下动态树分治。刷了一些比较基础的题目

一般都是存一下到这个重心的信息,然后再存这棵子树到上一层重心的信息,搞一搞就可以了

[COGS 2278]树黑白

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 200010
using namespace std;
typedef long long ll;
int n, m;
//-------------------------------------------------//
struct Edge{int to, nxt, dis;}edge[maxn << 1];
int h[maxn], cnt;
void add(int u, int v, int d){
	cnt ++;
	edge[cnt].to = v;
	edge[cnt].nxt = h[u];
	edge[cnt].dis = d;
	h[u] = cnt;
}
//-------------------------------------------------//
ll dis[maxn];
int dep[maxn], fa[maxn], anc[maxn][20];
void dfs(int u){
	dep[u] = dep[fa[u]] + 1;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(v == fa[u])continue;
		dis[v] = dis[u] + edge[i].dis;
		fa[v] = u;
		dfs(v);
	}
}

int ask_LCA(int p, int q){
	if(dep[p] < dep[q])swap(p, q);
	int log = 1;
	for(; 1 << log <= dep[p]; log ++); log --;
	for(int i = log; i >= 0; i --)
	    if(anc[p][i] && dep[anc[p][i]] >= dep[q])
	        p = anc[p][i];
	if(p == q)return p;
	for(int i = log; i >= 0; i --)
	    if(anc[p][i] && anc[p][i] != anc[q][i])
	        p = anc[p][i], q = anc[q][i];
	return fa[p];
}

ll dist(int p, int q){return dis[p] + dis[q] - 2 * dis[ask_LCA(p, q)];}
//-------------------------------------------------//
int g[maxn], size[maxn], G, Sum;
bool vis[maxn], check[maxn];
void Get_G(int u, int fa){
	size[u] = 1;
	int f = 0;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(v == fa || vis[v])continue;
		Get_G(v, u);
		size[u] += size[v];
		f = max(f, size[v]);
	}
	f = max(f, Sum - size[u]);
	if((f << 1) <= Sum)G = u;
}

void Divide(int u, int f){
	g[u] = f;
	vis[u] = true;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(vis[v])continue;
		Sum = size[v], G = v;
		Get_G(v, u);
		Divide(G, u);
	}
}
//-------------------------------------------------//

ll Node[maxn], Dis[maxn], Disf[maxn], ans;
int Standard;

void White(int u){
	Node[u] --;
	Dis[u] -= dist(u, Standard);
	if(g[u] == -1)return;
	Disf[u] -= dist(g[u], Standard);
	White(g[u]);
}

void Black(int u){
	Node[u] ++;
	Dis[u] += dist(u, Standard);
	if(g[u] == -1)return;
	Disf[u] += dist(g[u], Standard);
	Black(g[u]);
}

void ask(int u){
	ans += (Node[u] * dist(u, Standard) + Dis[u]);
	if(g[u] == -1)return;
	ans -= (Node[u] * dist(g[u], Standard) + Disf[u]);
	ask(g[u]);
}

int main(){
    freopen("A_Tree.in", "r", stdin);
	freopen("A_Tree.out", "w", stdout);
	scanf("%d%d", &n, &m);
	int u, v, d;
	for(int i = 1; i < n; i ++){
		scanf("%d%d%d", &u, &v, &d);
		add(u, v, d), add(v, u, d);
	}

	dfs(1); Sum = n;
	Get_G(1, -1), Divide(G, -1);
	for(int i = 1; i <= n; i ++)
	    anc[i][0] = fa[i];
	for(int j = 1; 1 << j <= n; j ++)
	    for(int i = 1; i <= n; i ++)
	        anc[i][j] = anc[anc[i][j-1]][j-1];
	char cmd[2];
	while(m --){
		scanf("%s%d", cmd, &u);
		Standard = u;
		if(cmd[0] == 'Q'){
			ans = 0;
			ask(u);
			printf("%lld\n", ans);
		}
		else{
			if(check[u])White(u);
			else Black(u);
			check[u] ^= 1;
		}
	}
	return 0;
}

[COGS 2258]复仇的序幕曲

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#define maxn 100010
using namespace std;

struct Edge{int to, nxt, dis;}edge[maxn << 1];
int h[maxn], cnt;
void add(int u, int v, int d){
	cnt ++;
	edge[cnt].to = v;
	edge[cnt].nxt = h[u];
	edge[cnt].dis = d;
	h[u] = cnt;
}

int n, m, a[maxn];

int dis[maxn], fa[maxn], anc[maxn][20], dep[maxn];
void dfs(int u){
	dep[u] = dep[fa[u]] + 1;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(v == fa[u])continue;
		fa[v] = u;
		dis[v] = dis[u] + edge[i].dis;
		dfs(v);
	}
}

int ask_LCA(int p, int q){
	if(dep[p] < dep[q])swap(p, q);
	int log = 1;
	for(; 1 << log <= dep[p]; log ++); log --;
	for(int i = log; i >= 0; i --)
		if(anc[p][i] && dep[anc[p][i]] >= dep[q])
		    p = anc[p][i];
	if(p == q)return p;
	for(int i = log; i >= 0; i --)
	    if(anc[p][i] && anc[p][i] != anc[q][i])
	        p = anc[p][i], q = anc[q][i];
	return fa[p];
}

int dist(int p, int q){
	return dis[p] + dis[q] - 2 * dis[ask_LCA(p, q)];
}

//-----------------------------------------------//
bool vis[maxn];
int g[maxn], size[maxn], G, Sum;
vector<pair<int, int> > V[maxn], F[maxn];

void Get_G(int u, int fa){
	int f = 0; size[u] = 1;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(vis[v] || v == fa)continue;
		Get_G(v, u);
		size[u] += size[v];
		f = max(f, size[v]);
	}
	f = max(f, Sum - size[u]);
	if((f << 1) <= Sum) G = u;
}

void Divide(int u, int f){
	g[u] = f, vis[u] = true;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(vis[v])continue;
		Sum = size[v], G = v;
		Get_G(v, u), Divide(G, u);
	}
}

int st, T, ans;

void update(int u){
	V[u].push_back(make_pair(dist(st, u), a[st]));
	F[u].push_back(make_pair(dist(st, g[u]), a[st]));
	if(g[u] > 0)update(g[u]);
}

int Binarysearch(vector<pair<int, int> > &V, int nw){
	if(V[0].first > nw)return 0;
	int l = 0, r = V.size() - 1;
	while(l < r){
		int m = l + (r - l + 1) / 2;
		if(V[m].first > nw)
			r = m - 1;
		else l = m;
	}
	return V[l].second;
}

void ask(int u){
	ans += Binarysearch(V[u], T - dist(u, st));
	if(g[u] == -1)return;
	int d = dist(g[u], st);
	ans -= Binarysearch(F[u], T - d);
	ask(g[u]);
}
//-----------------------------------------------//
int main(){
	freopen("SS.in", "r", stdin);
	freopen("SS.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i ++)
	    scanf("%d", &a[i]);
	int u, v, d;
	for(int i = 1; i < n; i ++){
		scanf("%d%d%d", &u, &v, &d);
		add(u, v, d), add(v, u, d);
	}
	
	dfs(1);
	for(int i = 1; i <= n; i ++)
	    anc[i][0] = fa[i];
	for(int j = 1; 1 << j <= n; j ++)
	    for(int i = 1; i <= n; i ++)
	        anc[i][j] = anc[anc[i][j-1]][j-1];
	Sum = n;
	Get_G(1, -1), Divide(G, -1);
	
	for(int i = 1; i <= n; i ++)
	    st = i, update(i);
	int sum = 0;
    for(int i = 1; i <= n; i ++){
		sort(V[i].begin(), V[i].end());
		sort(F[i].begin(), F[i].end());
		sum = 0;
		for(int j = 0; j < V[i].size(); j ++){
			sum += V[i][j].second;
			V[i][j].second = sum;
		}
		
		sum = 0;
		for(int j = 0; j < F[i].size(); j ++){
			sum += F[i][j].second;
			F[i][j].second = sum;
		}
    }
    
	while(m --){
		scanf("%d%d", &st, &T);
		ans = 0, ask(st);
		printf("%d\n", ans);
	}
	
	return 0;
}

[HNOI 2015]开店

并不清楚为什么要写G=v;这句话,难道找不到么。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#define maxn 150010
using namespace std;
typedef long long ll;
typedef vector<pair<int, ll> > vp;
int n, Q, A;

struct Edge{int to, nxt, dis;}edge[maxn << 1];
int h[maxn], cnt;
void add(int u, int v, int w){
	cnt ++;
	edge[cnt].to = v;
	edge[cnt].nxt = h[u];
	edge[cnt].dis = w;
	h[u] = cnt;
}


int a[maxn];

//-----------------------------------------------------//
int dep[maxn], fa[maxn], anc[maxn][20];
ll dis[maxn];
void dfs(int u){
	dep[u] = dep[fa[u]] + 1;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(v == fa[u])continue;
		fa[v] = u;
		dis[v] = dis[u] + edge[i].dis;
		dfs(v);
	}
}

void pre_LCA(){
	for(int i = 1; i <= n; i ++)
	    anc[i][0] = fa[i];
	for(int j = 1; 1 << j <= n; j ++)
		for(int i = 1; i <= n; i ++)
		    anc[i][j] = anc[anc[i][j-1]][j-1];
}

int ask_LCA(int p, int q){
	if(dep[p] < dep[q])swap(p, q);
	int log = 1;
	for(; 1 << log <= dep[p]; log ++); log --;
	for(int i = log; i >= 0; i --)
	    if(anc[p][i] && dep[anc[p][i]] >= dep[q])
	        p = anc[p][i];
	if(p == q)return p;
	for(int i = log; i >= 0; i --)
	    if(anc[p][i] && anc[p][i] != anc[q][i])
			p = anc[p][i], q = anc[q][i];
	return fa[p];
}

ll dist(int u, int v){
	return dis[u] + dis[v] - 2 * dis[ask_LCA(u, v)];
}

//-----------------------------------------------------//

int g[maxn], size[maxn], G, Sum;
vp V[maxn], F[maxn];
bool vis[maxn];

void Get_G(int u, int fa){
	size[u] = 1; int f = 0;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(v == fa || vis[v])continue;
		Get_G(v, u);
		size[u] += size[v];
		f = max(f, size[v]);
	}
	f = max(f, Sum - size[u]);
	if((f << 1) <= Sum)G = u;
}

void Divide(int u, int f){
	g[u] = f, vis[u] = true;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		if(vis[v])continue;
		Sum = size[v], G = v;
		Get_G(v, u), Divide(G, u);
	}
}

int St;

void update(int u){
	V[u].push_back(make_pair(a[St], dist(St, u)));
	if(g[u] < 0) return;
	F[u].push_back(make_pair(a[St], dist(St, g[u])));
	update(g[u]);
}

ll ans = 0;
int L, R;

int Bs(vp& V, ll nw){
	int l = 0, r = V.size() - 1;
	while(l < r){
		int m = l + (r - l + 1) / 2;
		if(V[m].first <= nw)l = m;
		else r = m - 1;
	}
	return l;
}

ll Binarysearch(vp &V, ll dis){
	if(V[0].first > R)return 0;
	if(V[V.size()-1].first < L)return 0;
	int ret1 = Bs(V, L-1), ret2 = Bs(V, R);
	return dis * (ret2 - ret1) + V[ret2].second - V[ret1].second;
}

void ask(int u){
	ans += Binarysearch(V[u], dist(St, u));
	if(g[u] < 0)return;
	ans -= Binarysearch(F[u], dist(St, g[u]));
	ask(g[u]);
}

int main(){
	freopen("shop_hnoi2015.in", "r", stdin);
	freopen("shop_hnoi2015.out", "w", stdout);
	scanf("%d%d%d", &n, &Q, &A);
	for(int i = 1; i <= n; i ++)
	    scanf("%d", &a[i]);
	int u, v, d; 
	for(int i = 1; i < n; i ++){
		scanf("%d%d%d", &u, &v, &d);
		add(u, v, d), add(v, u, d);
	}
	dfs(1), pre_LCA(), Sum = n;
	Get_G(1, -1), Divide(G, -1);
	for(int i = 1; i <= n; i ++)
	    update(St = i);
	for(int i = 1; i <= n; i ++){
		V[i].push_back(make_pair(-1, 0));
		F[i].push_back(make_pair(-1, 0));
		sort(V[i].begin(), V[i].end());
		sort(F[i].begin(), F[i].end());
		for(int j = 1; j < V[i].size(); j ++)
			V[i][j].second += V[i][j-1].second;
		for(int j = 1; j < F[i].size(); j ++)
		    F[i][j].second += F[i][j-1].second;
	}
	
	
	while(Q --){
		scanf("%d%d%d", &u, &L, &R);
		L = (L + ans) % A, R = (R + ans) % A;
		if(L > R)swap(L, R);
		St = u, ans = 0, ask(u);
		printf("%lld\n", ans);
	}

    return 0;
}

  

posted @ 2016-04-25 19:43  _Horizon  阅读(812)  评论(0编辑  收藏  举报