【树链剖分】重建


树剖裸题 = =单纯为了纪念一下我7K的代码


#include <cstdio>
#include <iostream>
#include <cstring>

using namespace std;

int read()
{
	int n = 0, sign = 1; char c = getchar();
	while(c < '0' || c > '9') { if(c == '-') sign = -1; c = getchar(); }
	while(c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }
	return sign * n;
}

const int Nmax = 100005;

int N, Q;
struct edge{
	int v, next;
}e[Nmax * 2];
int k = 1, head[Nmax];

inline void adde(int u, int v)
{
	e[k] = (edge){ v, head[u] };
	head[u] = k++;
}

int fa[Nmax], size[Nmax], son[Nmax], dep[Nmax];
int w[Nmax], ed[Nmax], top[Nmax], tot;

void dfs(int u)
{
	size[u] = 1;
	for(int i = head[u]; i; i = e[i].next)
	{
		int v = e[i].v;
		if(v == fa[u]) continue;
		fa[v] = u; dep[v] = dep[u] + 1;
		dfs(v); size[u] += size[v];
		if(size[v] > size[son[u]]) son[u] = v;
	}
}

void build_tree(int u, int tp)
{
	top[u] = tp; w[u] = ++tot;
	if(son[u]) build_tree(son[u], tp);
	for(int i = head[u]; i; i = e[i].next)
	{
		int v = e[i].v;
		if(v == fa[u] || v == son[u]) continue;
		build_tree(v, v);
	}
	ed[u] = tot;
}

#define lc (u << 1)
#define rc (u << 1 | 1)

struct SegmentTree{
	double sum[Nmax*4 + 1], mmin[Nmax*4 + 1], mmax[Nmax*4 + 1];
	double lazy[Nmax*4 + 1], ad[Nmax*4 + 1];
	
	inline void pushdown(int u, int l, int mid, int r)
	{
		if(lazy[u])
		{
			lazy[lc] = lazy[rc] = lazy[u];
			ad[lc] = ad[rc] = ad[u] = 0;
			mmin[lc] = mmax[lc] = lazy[u];
			sum[lc] = (mid - l + 1) * lazy[u];
			mmin[rc] = mmax[rc] = lazy[u];
			sum[rc] = (r - mid) * lazy[u];
			lazy[u] = 0;
		} 
		if(ad[u])
		{
			if(lazy[lc]) lazy[lc] += ad[u]; else ad[lc] += ad[u]; 
			if(lazy[rc]) lazy[rc] += ad[u]; ad[rc] += ad[u];
			mmin[lc] += ad[u]; mmax[lc] += ad[u];
			sum[lc] += (mid - l + 1) * ad[u];
			mmin[rc] += ad[u]; mmax[rc] += ad[u];
			sum[rc] += (r - mid) * ad[u];
			ad[u] = 0;
		}		
	}
	
	inline void pushup(int u)
	{
		sum[u] = sum[lc] + sum[rc];
		mmin[u] = min(mmin[lc], mmin[rc]);
		mmax[u] = max(mmax[lc], mmax[rc]);
	}
	
	void change(int u, int l, int r, int L, int R, double w)
	{
		if(l == L && r == R)
		{
			ad[u] = 0;
			lazy[u] = mmin[u] = mmax[u] = w;
			sum[u] = (r - l + 1) * w;
			return;
		}
		
		int mid = (l + r) >> 1; pushdown(u, l, mid, r);
		if(R <= mid) change(lc, l, mid, L, R, w);
		else if(L > mid) change(rc, mid + 1, r, L, R, w);
		else{
			change(lc, l, mid, L, mid, w);
			change(rc, mid + 1, r, mid + 1, R, w);
		}
		pushup(u);
	}
	
	void add(int u, int l, int r, int L, int R, double w)
	{
		if(l == L && r == R)
		{
			if(lazy[u]) lazy[u] += w; 
			else ad[u] += w;
			mmin[u] += w; mmax[u] += w;
			sum[u] += (r - l + 1) * w;
			return;
		}
		
		int mid = (l + r) >> 1; pushdown(u, l, mid, r);
		if(R <= mid) add(lc, l, mid, L, R, w);
		else if(L > mid) add(rc, mid + 1, r, L, R, w);
		else{
			add(lc, l, mid, L, mid, w);
			add(rc, mid + 1, r, mid + 1, R, w);
		}
		pushup(u);
	}
	
	double get_sum(int u, int l, int r, int L, int R)
	{
		if(l == L && r == R) return sum[u];
		
		int mid = (l + r) >> 1; pushdown(u, l, mid, r);
		if(R <= mid) return get_sum(lc, l, mid, L, R);
		else if(L > mid) return get_sum(rc, mid + 1, r, L, R);
		else return get_sum(lc, l, mid, L, mid) + get_sum(rc, mid + 1, r, mid + 1, R);
	}
	
	double get_min(int u, int l, int r, int L, int R)
	{
		if(l == L && r == R) return mmin[u];
		
		int mid = (l + r) >> 1; pushdown(u, l, mid, r);
		if(R <= mid) return get_min(lc, l, mid, L, R);
		else if(L > mid) return get_min(rc, mid + 1, r, L, R);
		else return min(get_min(lc, l, mid, L, mid),
						get_min(rc, mid + 1, r, mid + 1, R));
	}
	
	double get_max(int u, int l, int r, int L, int R)
	{
		if(l == L && r == R) return mmax[u];
		
		int mid = (l + r) >> 1; pushdown(u, l, mid, r);
		if(R <= mid) return get_max(lc, l, mid, L, R);
		else if(L > mid) return get_max(rc, mid + 1, r, L, R);
		else return max(get_max(lc, l, mid, L, mid),
						get_max(rc, mid + 1, r, mid + 1, R));
	}
}t;

double get_aver(int l, int r)
{
	int cnt = 0; double sum = 0;
	int f1 = top[l], f2 = top[r];
	while(f1 != f2)
	{
		if(dep[f1] < dep[f2]) { swap(f1, f2); swap(l, r); }
		cnt += w[l] - w[f1] + 1;
		sum += t.get_sum(1, 1, tot, w[f1], w[l]);
		l = fa[f1]; f1 = top[l];
	}
	if(dep[l] > dep[r]) swap(l, r);
	cnt += w[r] - w[l] + 1;
	sum += t.get_sum(1, 1, tot, w[l], w[r]);
	return sum / cnt;
}

void change(int l, int r, double aver)
{
	int f1 = top[l], f2 = top[r];
	while(f1 != f2)
	{
		if(dep[f1] < dep[f2]) { swap(f1, f2); swap(l, r); }
		t.change(1, 1, tot, w[f1], w[l], aver);
		l = fa[f1]; f1 = top[l];
	}
	if(dep[l] > dep[r]) swap(l, r);
	t.change(1, 1, tot, w[l], w[r], aver);
}

void add(int l, int r, double val)
{
	int f1 = top[l], f2 = top[r];
	while(f1 != f2)
	{
		if(dep[f1] < dep[f2]) { swap(f1, f2); swap(l, r); }
		t.add(1, 1, tot, w[f1], w[l], val);
		l = fa[f1]; f1 = top[l];
	}
	if(dep[l] > dep[r]) swap(l, r);
	t.add(1, 1, tot, w[l], w[r], val);
}

double Max, Min, Sum;
void get_every(int l, int r)
{
	Max = -1e100, Min = 1e100, Sum = 0. ;
	int f1 = top[l], f2 = top[r];
	while(f1 != f2)
	{
		if(dep[f1] < dep[f2]) { swap(f1, f2); swap(l, r); }
		Max = max(Max, t.get_max(1, 1, tot, w[f1], w[l]));
		Min = min(Min, t.get_min(1, 1, tot, w[f1], w[l]));
		Sum += t.get_sum(1, 1, tot, w[f1], w[l]);
		l = fa[f1]; f1 = top[l];
	}
	if(dep[l] > dep[r]) swap(l, r);
	Max = max(Max, t.get_max(1, 1, tot, w[l], w[r]));
	Min = min(Min, t.get_min(1, 1, tot, w[l], w[r]));
	Sum += t.get_sum(1, 1, tot, w[l], w[r]);
}

int main()
{
	freopen("rebd.in", "r", stdin);
	freopen("rebd.out", "w", stdout);
	
	getchar();
	N = read(); Q = read();
	for(int i = 1; i < N; ++i) 
	{
		int u = read(), v = read();
		adde(u, v); adde(v, u);
	}
	dfs(1); build_tree(1, 1);
	
	char sign[10]; int a, b; double v;
	while(Q--)
	{
		scanf("%s", sign);

		if(!strcmp(sign, "F")) {
			a = read(); b = read();
			double aver = get_aver(a, b);
			change(a, b, aver);
		} else if(!strcmp(sign, "N")) {
			a = read(); b = read();
			scanf("%lf", &v);
			add(a, b, v);
		} else if(!strcmp(sign, "C")){
			a = read(); b = read();
			get_every(a, b);
			printf("%.6f %.6f %.6f\n", Min, Max, Sum);
		} else if(!strcmp(sign, "FF")){
			a = read();
			double aver = t.get_sum(1, 1, tot, w[a], ed[a]) / (ed[a] - w[a] + 1);
			t.change(1, 1, tot, w[a], ed[a], aver);
		} else if(!strcmp(sign, "NN")){
			a = read();
			scanf("%lf", &v);
			t.add(1, 1, tot, w[a], ed[a], v);
		} else {
			a = read();
			Min = t.get_min(1, 1, tot, w[a], ed[a]);
			Max = t.get_max(1, 1, tot, w[a], ed[a]);
			Sum = t.get_sum(1, 1, tot, w[a], ed[a]);
			printf("%.6f %.6f %.6f\n", Min, Max, Sum);
		}
		//for(int i = 1; i <= 13; ++i) printf("%d : %.6f %.6f %.6f\n", i, t.mmin[i], t.mmax[i], t.sum[i]);
		//puts("");
	}
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值