codeforce 342E 树链剖分 || 分块

题目链接:http://codeforces.com/problemset/problem/342/E

树链剖分代码:

#include<stdio.h>
#include<memory.h>
#include<algorithm>
#include<vector>
using namespace std;
#define yt eg[i].to
#define lson l,m,a[rt].ls
#define rson m+1,r,a[rt].rs
#define pb push_back
const int N=100005,inf=1000001;
int cnt,v[N],fa[N],top[N],w[N],dep[N],size[N],son[N];
//size[i]以i为根的子树节点数
//son[i] i的子树中,节点数最多的儿子节点
int dis[N],root[N],id,sz;
vector<int> lk[N];

inline int min(int a,int b){return a<b?a:b;}

struct node{
	int opt,ml,mr,ls,rs;
}a[N<<2];

struct edge{
	int to,next;
}eg[N<<1];
void add(int x,int y){
	eg[cnt].to=y;
	eg[cnt].next=v[x];
	v[x]=cnt++;
}
int pushup(int rt){
	int ls=a[rt].ls,rs=a[rt].rs;
	a[rt].ml=min(a[ls].ml,a[rs].ml);
	a[rt].mr=min(a[ls].mr,a[rs].mr);
}
int dfs1(int x){//得到重链
	son[x]=0, size[x]=1;
	for(int i=v[x];i!=-1;i=eg[i].next){
		if(yt==fa[x]) continue;
		fa[yt] = x;
		dep[yt] = dep[x]+1;
		dfs1(yt);
		size[x] += size[yt];
		if(size[yt] > size[son[x]]) son[x] = yt;
	}
}
int dfs2(int x,int tp){//转成1为根的有根树 对于多个子节点先走重链 再走轻边,这样可以使重链在线段树中连续分布
	top[x] = tp;//x的所在重链的顶端节点
	int sz = lk[tp].size();
	w[x] = sz, lk[tp].pb(x);//w[i] 表示lk数组中所在的位置 lk[ top[i] ][w[i]] = i(线段树中的位置)
	if(son[x]) 
		dfs2(son[x], tp);
	for(int i = v[x]; ~i ; i = eg[i].next)
		if(yt != son[x] && yt != fa[x]) 
			dfs2(yt, yt);
}
void build(int tp,int l,int r,int rt){
	a[rt].ml = a[rt].mr = inf;
	if(l == r) return;
	int m = (l + r)>>1;
	a[rt].ls = id++, a[rt].rs = id++;
	build(tp,lson),build(tp,rson);
}
void update(int p, int c, int l, int r, int rt){
	if(l == r)
	{
		a[rt].ml = l+c;
		a[rt].mr = sz-1-l+c;
		return;
	}
	int m = (l+r)>>1;
	if(p <= m) update(p, c, lson);
	else update(p, c, rson);
	pushup(rt);
}
int query(int L, int R, int k, int l, int r, int rt){
	if(L <= l && r<= R){
		if(!k) return a[rt].ml;
		else return a[rt].mr;
	}
	int m = (l + r)>>1, ret = inf;
	if(L<=m) ret = min(ret, query(L, R, k, lson));
	if(R >m) ret = min(ret, query(L, R, k, rson));
	return ret;
}
int main(){
	int T, op, n, m, i, j, k, x, y, c, f1, f2, t, d, tp, res;
	while(~scanf("%d %d", &n, &m))
	{
		for(i = 1;i <= n; i++) dis[i] = inf,lk[i].clear();
		memset(v, -1, sizeof(v));
		memset(fa, 0, sizeof(fa));
		for(i = cnt = 0;i < n-1; i++)
		{
			scanf("%d %d", &x, &y);
			add(x, y), add(y, x);
		}
		dep[1] = dis[1] = 0, dfs1(1);
		id = cnt = 0, dfs2(1, 1);
		for(i = 1;i <= n; i++)
		{
			sz = lk[i].size();
			if(top[i] == i && sz != 1)//若i是重链起点 且i不是叶子节点 也就是有重链时
			{
				root[i] = id ++;
				build(i, 0, sz-1, root[i]);
			}
		}
		sz = lk[1].size();
		update(0, 0, 0, sz-1, root[1]);
		while(m--)
		{
			scanf("%d%d", &op, &x);
			if(op==1)
			{
				for(y = x; y ;y = fa[tp])
				{
					tp = top[y];
					sz = lk[tp].size();
					if(dis[y] > dep[x] - dep[y])
					{
						dis[y] = dep[x] - dep[y];
						if(sz > 1) update(w[y], dis[y], 0, sz-1, root[tp]);
					}
					else break;
				}
			}
			else{
				for(res = inf, y = x; y ; y = fa[tp]){
					tp = top[y];
					sz = lk[tp].size();
					if(sz == 1) res = min(res, dis[y] + dep[x] - dep[y]);
					else{
						res=min(res,query(0,w[y],1,0,sz-1,root[tp])+w[y]-(sz-1)+dep[x]-dep[y]);
						res=min(res,query(w[y],sz-1,0,0,sz-1,root[tp])-w[y]+dep[x]-dep[y]);
					}
				}
				printf("%d\n",res);
			}
		}
	}
	return 0;
}


 

 分块代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<cassert>
#include<algorithm>
#include<iostream>
#include<string>
#include<deque>
#include<vector>
#include<queue>
#include<list>
#include<stack>
#include<set>
#include<map>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=(int)1e5+10;
vector<int>G[N],black,white;
int dep[N],dp[N];
const int Pow = 18;
int par[N][Pow];
void dfs(int u,int pre){
	dep[u] = dep[pre] + 1;
	par[u][0] = pre;
	for(int i=1;i<Pow;i++)par[u][i] = par[par[u][i-1]][i-1];
	for(int i=0;i<G[u].size();i++){
		int v = G[u][i];
		if(v == pre)continue;
		dfs(v,u);
	}
}
int LCA(int a,int b){
	if(dep[a] > dep[b])swap(a,b);
	if(dep[a] < dep[b]){
		int del = dep[b] - dep[a];
		for(int i=0;i<Pow;i++)
			if(del&(1<<i))b = par[b][i];
	}
	if(a!=b){
		for(int i=Pow-1;i>=0;i--)
			if(par[a][i] != par[b][i])
				a = par[a][i],b = par[b][i];
		a = par[a][0],b = par[b][0];
	}
	return a;
}
void bfs(){
	queue<int>Q;
	for(int i=0;i<black.size();i++){
		Q.push(black[i]);dp[black[i]] = 0;
	}
	while(!Q.empty()){
		int u = Q.front();Q.pop();
		for(int i=0;i<G[u].size();i++){
			int v =G[u][i];
			if(dp[v] > dp[u] + 1){
				dp[v] = dp[u] + 1;
				Q.push(v);
			}
		}
	}
	black.clear();
}
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		for(int i=1;i<=n;i++)G[i].clear();
		for(int i=1;i<=n;i++)dp[i] = ~0u>>2;
		black.clear();black.push_back(1);
		for(int i=1;i<n;i++){
			int u,v;scanf("%d%d",&u,&v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		dfs(1,0);
		bfs();int maxn = sqrt(m*1.0) + 1;
		for(int i=0;i<m;i++){
			int op,u;
			scanf("%d%d",&op,&u);
			if(op==1){
				black.push_back(u);
				if(black.size() == maxn){
					bfs();
				}
			}else{
				int sz = black.size();
				int ans = dp[u];
				for(int i=0;i<sz;i++){
					int v = black[i];
					ans = min(ans,dep[u] + dep[v] - 2*dep[LCA(u,v)]);
				}
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}


 

你可能感兴趣的:(codeforce 342E 树链剖分 || 分块)