SPOJ 375 QTREE (树链剖分入门题)

来源:互联网 发布:mysql主从复制配置 编辑:程序博客网 时间:2024/06/06 02:59

题目大意:对一棵有n(n<=10000)个点的树若干次操作,每次操作可以把第i条边的权值改为w,或者求u节点到v节点的路径上所有边的最大权值。

解题思路:对这棵树进行树链剖分,然后用线段树维护区间最大值。

树链剖分理解:通过规定一种特殊的次序,将树形结构变为线性结构,从而可以用多种数据结构来解决树上路径方面的问题。

AC代码:

/*    @Author: wchhlbt    @Date:   2017/7/22*/#include <bits/stdc++.h>#define Fori(x) for(int i=0;i<x;i++)#define Forj(x) for(int j=0;j<x;j++)#define maxn 10005#define inf 0x3f3f3f3f#define ONES(x) __builtin_popcount(x)#define pb push_back#define _  << "  " <<using namespace std;typedef long long ll ;const double eps =1e-8;const int mod = 1000000007;typedef pair<int, int> P;const double PI = acos(-1.0);int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};int n,m;int ans;int cnt;struct edge{    int u,v,val;    void read(){        scanf("%d%d%d",&u,&v,&val);    }}edge[maxn];vector<int> e[maxn];/*树链剖分    cnt初始化为0    son数组初始化为-1    getans()根据实际维护的值进行修改*/int son[maxn];//重儿子int size[maxn];//子数大小int fa[maxn];//父节点int dep[maxn];//深度void dfs1(int u, int f, int d)//维护重儿子,深度,父节点,子树大小{    size[u] = 1;//初始化size    fa[u] = f;//标注父节点    dep[u] = d;    son[u] = 0;//初始化重儿子编号为0    for(int i = 0; i<e[u].size(); i++){        int v = e[u][i];        if(v==f)    continue;        dfs1(v,u,d+1);        size[u] += size[v];        if(size[v]>size[son[u]])            son[u] = v;    }}int id[maxn];int top[maxn];//dfs2建立重链void dfs2(int u, int tp)//tp为当前重链的起始点{    top[u] = tp;    id[u] = ++cnt;    if(son[u]!=-1)  dfs2(son[u],tp);    for(int i = 0; i<e[u].size(); i++){        int v = e[u][i];        if(v==fa[u] || v==son[u])    continue;        dfs2(v,v);    }}//线段树int val[maxn];//区间最大值线段树  支持单点修改struct NODE{    int l,r,val;} node[4*maxn];int build(int root, int l, int r){    node[root].l = l;    node[root].r = r;    if(l==r)        return node[root].val = val[l];    int mid = (l+r)>>1;    int a = build(root<<1, l, mid);    int b = build(root<<1 | 1 ,mid+1, r);    return node[root].val = max(a,b);}int update(int root, int pos, int val)//将pos位置的值替换为val{    if (pos < node[root].l || pos > node[root].r)        return node[root].val;    if (node[root].l == pos && node[root].r == pos)        return node[root].val = val;    int a = update (root<<1, pos, val);    int b = update (root<<1 | 1 , pos, val);    node[root].val = max(a,b);    return node[root].val;}int query(int root, int l, int r){    if(l>node[root].r || r<node[root].l)//无交集        return 0;    if(l<=node[root].l && node[root].r<=r)//此区间包含root所管理的区间        return node[root].val;    int a = query(root<<1, l, r);//部分相交    int b = query(root<<1 | 1 ,l, r);    return max(a,b);}/*****************************************/int getans(int u, int v){    int tp1 = top[u]; int tp2 = top[v];    int ans = 0;    while(tp1!=tp2){        if(dep[tp2]>dep[tp1]){            swap(u,v);            swap(tp1,tp2);        }        int temp = query(1,id[tp1],id[u]);//考虑tp1上面的轻链        ans = max(ans,temp);        u = fa[tp1];    tp1 = top[u];//更新u节点为重链头节点的父节点    }    if(u==v)    return ans;    //处理u、v在一条重链上的情况    if(dep[v]>dep[u])   swap(u,v),swap(tp1,tp2);    int temp = query(1,id[son[v]],id[u]);    ans = max(ans,temp);    return ans;}void init()//全部初始化操作{    cnt = 0;//重新编号树上的id    memset(son,-1,sizeof(son));    for(int i = 0; i<maxn-2; i++)        e[i].clear();}int main(){    //freopen("test.txt","r",stdin);    int t;    scanf("%d",&t);    while(t--){        init();        scanf("%d",&n);        for(int i = 1; i<n; i++){            edge[i].read();            e[edge[i].u].pb(edge[i].v);            e[edge[i].v].pb(edge[i].u);        }        dfs1(1,0,1);        dfs2(1,1);        for (int i = 1; i < n; i++) {//将u节点调整成更深的节点            if (dep[edge[i].u] < dep[edge[i].v]) swap(edge[i].u, edge[i].v);            val[id[edge[i].u]] = edge[i].val;        }        build(1,1,cnt);        char s[200];        while(~scanf("%s",&s) && s[0]!='D'){            int x,y;            scanf("%d%d",&x,&y);            if(s[0]=='Q')                printf("%d\n",getans(x,y));            else                update(1,id[edge[x].u],y);//单点更新        }    }    return 0;}/*unsigned   int   0~4294967295int   2147483648~2147483647unsigned long 0~4294967295long   2147483648~2147483647long long的最大值:9223372036854775807long long的最小值:-9223372036854775808unsigned long long的最大值:18446744073709551615__int64的最大值:9223372036854775807__int64的最小值:-9223372036854775808unsigned __int64的最大值:18446744073709551615*/