SPOJ 375 Query on a tree[树链剖分入门]
来源:互联网 发布:php过滤数组重复数据 编辑:程序博客网 时间:2024/05/20 19:18
原文地址:树链剖分[若侵权,请私信,必删]
“在一棵树上进行路径的修改、求极值、求和”乍一看只要线段树就能轻松解决,实际上,仅凭线段树是不能搞定它的。我们需要用到一种貌似高级的复杂算法——树链剖分。
**数据规模大时,递归可能会爆栈,而非递归dfs会很麻烦,所以可将两个dfs改为宽搜+循环。即先宽搜求出fa、dep,然后逆序循环求出siz、son,再顺序循环求出top和w。
#include <cstdio>#include <algorithm>#include <iostream>#include <string.h>using namespace std;const int maxn = 10010;struct Tedge{ int b, next; } e[maxn * 2];int tree[maxn];int zzz, n, z, edge, root, a, b, c;int d[maxn][3];int first[maxn], dep[maxn], w[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn];char ch[10];void insert(int a, int b, int c){ e[++edge].b = b; e[edge].next = first[a]; first[a] = edge;}void dfs(int v){ siz[v] = 1; son[v] = 0; for (int i = first[v]; i > 0; i = e[i].next) if (e[i].b != fa[v]) { fa[e[i].b] = v; dep[e[i].b] = dep[v]+1; dfs(e[i].b); if (siz[e[i].b] > siz[son[v]]) son[v] = e[i].b; siz[v] += siz[e[i].b]; }}void build_tree(int v, int tp){ w[v] = ++ z; top[v] = tp; if (son[v] != 0) build_tree(son[v], top[v]); for (int i = first[v]; i > 0; i = e[i].next) if (e[i].b != son[v] && e[i].b != fa[v]) build_tree(e[i].b, e[i].b);}void update(int root, int lo, int hi, int loc, int x){ if (loc > hi || lo > loc) return; if (lo == hi) { tree[root] = x; return; } int mid = (lo + hi) / 2, ls = root * 2, rs = ls + 1; update(ls, lo, mid, loc, x); update(rs, mid+1, hi, loc, x); tree[root] = max(tree[ls], tree[rs]);}int maxi(int root, int lo, int hi, int l, int r){ if (l > hi || r < lo) return 0; if (l <= lo && hi <= r) return tree[root]; int mid = (lo + hi) / 2, ls = root * 2, rs = ls + 1; return max(maxi(ls, lo, mid, l, r), maxi(rs, mid+1, hi, l, r));}inline int find(int va, int vb){ int f1 = top[va], f2 = top[vb], tmp = 0; while (f1 != f2) { if (dep[f1] < dep[f2]) { swap(f1, f2); swap(va, vb); } tmp = max(tmp, maxi(1, 1, z, w[f1], w[va])); va = fa[f1]; f1 = top[va]; } if (va == vb) return tmp; if (dep[va] > dep[vb]) swap(va, vb); return max(tmp, maxi(1, 1, z, w[son[va]], w[vb])); //}void init(){ scanf("%d", &n); root = (n + 1) / 2; fa[root] = z = dep[root] = edge = 0; memset(siz, 0, sizeof(siz)); memset(first, 0, sizeof(first)); memset(tree, 0, sizeof(tree)); for (int i = 1; i < n; i++) { scanf("%d%d%d", &a, &b, &c); d[i][0] = a; d[i][1] = b; d[i][2] = c; insert(a, b, c); insert(b, a, c); } dfs(root); build_tree(root, root); // for (int i = 1; i < n; i++) { if (dep[d[i][0]] > dep[d[i][1]]) swap(d[i][0], d[i][1]); update(1, 1, z, w[d[i][1]], d[i][2]); }}inline void read(){ ch[0] = ' '; while (ch[0] < 'C' || ch[0] > 'Q') scanf("%s", &ch);}void work(){ for (read(); ch[0] != 'D'; read()) { scanf("%d%d", &a, &b); if (ch[0] == 'Q') printf("%d\n", find(a, b)); else update(1, 1, z, w[d[a][1]], b); }}int main(){ for (scanf("%d", &zzz); zzz > 0; zzz--) { init(); work(); } return 0;}
附上博主的丑代码=-=:
#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>#define ll long long#define maxn 50008#define maxm 100008using namespace std;inline void read(int &x){ char ch; bool flag=false; for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true; for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); x=flag?-x:x;}inline void write(int x){ static const int maxlen=100; static char s[maxlen]; if (x<0) { putchar('-'); x=-x;} if(!x){ putchar('0'); return; } int len=0; for(;x;x/=10) s[len++]=x % 10+'0'; for(int i=len-1;i>=0;--i) putchar(s[i]);} //pos指该点到父亲的边在边序列的编号,得到边序列后便可用数据结构来处理 //top指该点所在重链的起点//fa 该点的父亲节点, son该点的重儿子 ,size 该点的子树的节点数 int fa[maxn],son[maxn],deep[maxn],top[maxn],size[maxn],pos[maxn]; int kk[maxn][8];//记录边 int ed[maxm],pre[maxm],now[maxn],v[maxm],tot;void build(int a,int b,int c){pre[++tot]=now[a];now[a]=tot;ed[tot]=b;v[tot]=c;} int sum;//sum指序列总大小; void dfs(int x){size[x]=1; son[x]=0; for (int p=now[x];p;p=pre[p]) if (ed[p]!=fa[x]) { int y=ed[p]; fa[y]=x; deep[y]=deep[x]+1; dfs(y); if (size[y]>size[son[x]]) son[x]=y; size[x]+=size[y]; }}//第一遍求deep,size,son void dfs2(int x,int topp){pos[x]=++sum; top[x]=topp;if (son[x]) dfs2(son[x],topp);for (int p=now[x];p;p=pre[p]) if (ed[p]!=fa[x]) if (ed[p]!=son[x]) dfs2(ed[p],ed[p]);}//第二遍求pos,top int tree[maxn*7]; void change(int l,int r,int p,int a,int b){if ((l==a)&&(r==a)) { tree[p]=b; return; }int mid=(l+r)/2;if (a<=mid) change(l,mid,p*2,a,b);else change(mid+1,r,p*2+1,a,b);tree[p]=max(tree[p*2],tree[p*2+1]);} int find(int l,int r,int p,int a,int b){if ((l==a)&&(r==b)) return tree[p];int mid=(l+r)/2;if (b<=mid) return find(l,mid,p*2,a,b);else if (a>mid) return find(mid+1,r,p*2+1,a,b); else return max(find(l,mid,p*2,a,mid),find(mid+1,r,p*2+1,mid+1,b)); } int get(int a,int b){int f1=top[a],f2=top[b],ans=0; while (f1!=f2){ if(deep[f1]<deep[f2]) { swap(f1,f2); swap(a,b); } ans=max(ans,find(1,sum,1,pos[f1],pos[a])); a=fa[f1];f1=top[a]; } if(a==b) return ans; if (deep[a]>deep[b]) swap(a,b); return max(ans,find(1,sum,1,pos[son[a]],pos[b]));}//每次取深度大的点向上跳,直到两点在同一重链 int n; void init(){read(n);memset(now,0,sizeof(int)*(n+1));memset(tree,0,sizeof(int)*(n+1)*7);int root =1;tot=0; sum=0;deep[root]=0;fa[root]=0;for (int i=1;i<n;i++){ int a,b,c; read(a); read(b); read(c); kk[i][0]=a; kk[i][1]=b; kk[i][2]=c; build(a,b,c); build(b,a,c); }dfs(root);dfs2(root,root);for (int i=1;i<n;i++){ if (deep[kk[i][0]]>deep[kk[i][1]]) swap(kk[i][0],kk[i][1]);//保证每条边均由父亲节点指向子节点 change(1,sum,1,pos[kk[i][1]],kk[i][2]); }} char ch[200]; void rreadd(){ch[0]=' '; while (ch[0] < 'C' || ch[0] > 'Q') scanf("%s", &ch);} void doit(){ for (rreadd();ch[0]!='D';rreadd()) { int a,b; read(a); read(b); if (ch[0]=='Q') { write(get(a,b)); puts("");} else change(1,sum,1,pos[kk[a][1]],b); }} int main(){int ca;read(ca);for (int i=1;i<=ca;i++) { init(); doit(); }return 0;}
- SPOJ 375 Query on a tree[树链剖分入门]
- [SPOJ 375]Query On a Tree(树链剖分)
- spoj 375--Query On a Tree [树链剖分]
- spoj 375 Query on a tree 树链剖分
- SPOJ 375 Query on a tree(树链剖分)
- SPOJ 375. Query on a tree (树链剖分入门)
- spoj 375 Query on a tree
- SPOJ 375 Query on a tree
- SPOJ 375 Query on a tree
- SPOJ 375. Query on a tree【树链剖分】
- SPOJ 375. Query on a tree【树链剖分】
- SPOJ QTREE(Query on a tree树链剖分)
- spoj 375. Query on a tree(树链剖分)
- SPOJ QTREE Query on a tree --树链剖分
- [ SPOJ - QTREE]Query on a tree && 树链剖分
- SPOJ Query on a tree (树链剖分)
- SPOJ QTREE Query on a tree 树链剖分
- SPOJ QTREE Query on a tree 树链剖分
- 表单验证 bootstrap- validate.js
- LXT6架构-国产FPGA分析(2016版)
- linux ln
- android Intent调用地图应用客户端
- samba访问window共享 解决中文乱码
- SPOJ 375 Query on a tree[树链剖分入门]
- 毕设项目总结之序章
- vector的使用
- 美国司法制度
- response.sendRedirect()与request.getRequestDispatcher().forward(request,response)的区别
- Linux命令大全
- cordova 插件 BarcodeScanne 二维码扫描
- redhat下的环境搭建
- ArcGis Engine编程之子集、选择集和版面视图