SPOJ 375 树链剖分

模板


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
using namespace std;
#define lson (pos<<1)
#define rson (pos<<1|1)

const int maxn = 100100;
const int inf = 0x7fffffff;

//----建边部分
struct Vector_edge//存vector用的东西
{
	int v, w;
	Vector_edge():v(0),w(0){}
	Vector_edge(int a, int b):v(a),w(b){}
};
vector<Vector_edge>g[maxn];

struct edge
{
	int to, next;
}e[maxn];

inline void add_edge(int a, int b, int c)
{
	g[a].push_back(Vector_edge(b,c));
}
//----树链部分=====
int dfs_clock, cnt;
struct node
{
	int size, dep, son, top, fa, ti;
	node():size(0),dep(0),son(0),top(0),fa(0),ti(0){};
	//size:v为跟节点数量
	//dep:v的深度 根为1
	//top:v所在链的顶端
	//son:vv在同一重链的儿子节点,重儿子
	//ti:v与父亲的连边,在线段树中的位置
}t[maxn];

void dfs_find(int u, int pa, int depth)
{
	//cout<<u<<" "<<pa<<" "<<depth<<endl;
	t[u].son = 0;
	t[u].size = 1;
	t[u].dep = depth;
	t[u].fa = pa;
	for (int i = 0; i != g[u].size(); ++ i)
	{
		int v = g[u][i].v;
		if (v == pa)	continue;
		dfs_find(v, u, depth + 1);
		t[u].size += t[v].size;
		//if (t[u].son == -1)	t[u].son = v;
		if (t[v].size > t[t[u].son].size)	t[u].son = v;
	}
}

void dfs_time(int u, int pa)
{
	t[u].ti = ++ dfs_clock; t[u].top = pa;
	if (t[u].son != 0)	dfs_time(t[u].son, t[u].top);
	for (int i = 0; i != g[u].size(); ++ i)
	{
		int v = g[u][i].v;
		if (v == t[u].son || v == t[u].fa)	continue;
		dfs_time(v, v);
	}
}
//----线段树部分--
struct xianduan_node
{
	int l,r,val,mx;
	int mid(){return (l+r)>>1;}
}tree[maxn<<2];

void build(int pos, int l, int r)
{
	tree[pos].l = l;
	tree[pos].r = r;
	tree[pos].mx = tree[pos].val = - inf;
	if (l == r)	return;
	int mid = tree[pos].mid();
	build(lson,l,mid);
	build(rson, mid + 1, r);
}

void update(int pos, int id, int w)// id改为w
{
	if (tree[pos].l == tree[pos].r)
	{
		tree[pos].mx = tree[pos].val = w;
		return ;
	}
	int mid = tree[pos].mid();
	if (mid >= id)	update(lson, id, w);
	else update(rson, id, w);
	tree[pos].mx = max(tree[lson].mx, tree[rson].mx);
}

int query(int pos, int L, int R)
{
	//cout<<L<<" "<<R<<" "<<pos<<" "<<tree[pos].l<<" "<<tree[pos].r<<" "<<tree[pos].mx<<endl;
	if (L <= tree[pos].l && tree[pos].r <= R)	
		return tree[pos].mx;
	int mid = tree[pos].mid();
	int ans = - inf;
	if (mid >= L)	ans = max(ans, query(lson, L, R));
	if (mid < R)	ans = max(ans, query(rson, L, R));
	return ans;
}


int lca(int x, int y)
{
	int ans = -inf;
	while (t[x].top != t[y].top)
	{
		if (t[t[x].top].dep < t[t[y].top].dep)	swap(x,y);
		ans = max(ans, query(1, t[t[x].top].ti, t[x].ti));
		x = t[t[x].top].fa;
	}
	if (t[x].dep > t[y].dep)	swap(x, y);
	//cout<<x<<" "<<y<<endl;
	//cout<<ans<<endl;
	//cout<<t[x].ti<<" "<<t[y].ti<<endl;
	//cout<<endl<<endl;
	if (x != y)	ans = max(ans , query(1, t[x].ti + 1, t[y].ti));
	////这里的t[x].ti指的是x与其父亲的边,所以一定注意+1
	return ans;
}

int n;
int da[maxn][3];
void clear()
{
	cnt = dfs_clock = 0;
	for (int i = 0; i != maxn; ++ i)	g[i].clear();
}

int main()
{
	int T; scanf("%d", &T);
	while (T--)
	{
		clear();
		scanf("%d", &n);
		for (int i = 1; i < n; ++ i)
		{
			scanf("%d%d%d", &da[i][0], &da[i][1], &da[i][2]);
			add_edge(da[i][0], da[i][1], da[i][2]);
			add_edge(da[i][1], da[i][0], da[i][2]);
		}
		dfs_find(1, 1, 1);
		dfs_time(1, 1);
		build(1, 2, n);//因为1没有前驱边,1是树根
		for (int i = 1; i < n; i ++ )
		{
			if (t[da[i][0]].dep > t[da[i][1]].dep)
				swap(da[i][0] , da[i][1]);
			update(1, t[da[i][1]].ti, da[i][2]);
		}
        	char he[100];
	        while(1)
        	{
	            scanf("%s",he);
        	    if(he[0]=='D')break;
	            if(he[0]=='Q')
        	    {
                	int a,b;scanf("%d%d",&a,&b);
	                printf("%d\n",lca(a,b));
        	    }
	            else
        	    {
	                int a,b;scanf("%d%d",&a,&b);
        	        update(1,t[da[a][1]].ti,b);
	            }
        	}
	        printf("\n");
	}
	return 0;
}
/*
1
5
1 2 3
1 3 1
3 4 3
1 5 3
QUERY 1 4
DONE

*/


你可能感兴趣的:(SPOJ 375 树链剖分)