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*/
阅读全文
0 0
- SPOJ 375 QTREE (树链剖分入门题)
- 树链剖分模板+入门题 SPOJ - QTREE
- Spoj 375 QTREE(树链剖分)
- Spoj 375 Qtree 树链剖分 + 线段树 解法
- SPOJ 375 QTREE POJ 3237 TREE 树链剖分
- SPOJ 375 QTREE
- spoj 375 QTREE
- spoj 375 QTREE
- SPOJ-375 QTREE
- SPOJ - QTREE (树链剖分)
- 【SPOJ QTREE】树链剖分模板
- SPOJ QTREE(树链剖分)
- spoj 375 qtree 动态树
- 树链剖分学习笔记 && SPOJ QTREE
- SPOJ QTREE(树链剖分模板)
- SPOJ - QTREE 375 Query on a tree 树链剖分+线段树
- SPOJ 375 QTREE系列-Query on a tree (树链剖分)
- SPOJ 题目 375 QTREE - Query on a tree(树链剖分)
- 如何管理团体
- elasticsearch 快照与恢复
- Spring 容器
- App测试方法总结
- Java人员正确使用 IntelliJ IDEA的方式
- SPOJ 375 QTREE (树链剖分入门题)
- android网络初探--WebView的使用
- setInterval 实现定时调用的函数
- vue学习知识总结
- QGroundControl 3.2 开发环境搭建
- Java中的多线程你只要看这一篇就够了
- 1012. 数字分类 (20)
- 1060. Are They Equal 解析
- JavaScript中高阶函数