树链剖分 spoj 375 Query on a tree(剖分入门)
2016-05-05 14:42
513 查看
题目链接
树链剖分学习
树链剖分并不是一个复杂的算法或者数据结构,只是能把一棵树拆成链来处理而已,换一种说法,树链剖分只是xxx数据结构/算法在树上的推广,或者说,树链剖分只是把树hash到了几段连续的区间上。
树链剖分学习
树链剖分并不是一个复杂的算法或者数据结构,只是能把一棵树拆成链来处理而已,换一种说法,树链剖分只是xxx数据结构/算法在树上的推广,或者说,树链剖分只是把树hash到了几段连续的区间上。
#include<bits/stdc++.h> using namespace std; #define LL long long #define cl(a,b) memset(a,b,sizeof(a)) #define pb push_back #define gcd __gcd const int maxn = 100010; const LL inf =1LL<<50; const LL mod1 = 1000000007; struct Edge{ int to,next; }edge[maxn]; int head[maxn],tot; void addedge(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } ////////////////////////////////////////////// int top[maxn];//top[v]表示v所在的重链的顶端节点 int num[maxn];//num[v]表示以v为根的子树的节点数 int deep[maxn];//深度 int fa[maxn];//fa[v]表示v的父亲节点 int p[maxn];//p[v]表示v与父亲的边在线段树的位置 int fp[maxn];//和p数组是相反的意思 int son[maxn];//son[u]表示u的重儿子节点 int pos;//剖分时候编号,对应于线段树中的位置 void dfs1(int u,int pre,int d){//计算出fa,deep,num,son deep[u]=d; fa[u]=pre; num[u]=1; for(int i=head[u];~i;i=edge[i].next){ int v = edge[i].to; if(v==pre)continue; dfs1(v,u,d+1); num[u]+=num[v]; if(son[u]==-1||num[v]>num[son[u]]) son[u]=v; } } void dfs2(int u,int sp){//计算top和p top[u]=sp; if(son[u]!=-1){ p[u]=pos++; fp[p[u]]=u; dfs2(son[u],sp); } else { p[u]=pos++; fp[p[u]]=u; return ; } for(int i=head[u];~i;i=edge[i].next){ int v = edge[i].to; if(v != son[u] && v != fa[u]){ dfs2(v,v); } } } ////////////////////////////////////////////////// void init(){ tot=0; cl(head,-1); pos=1; cl(son,-1); } int segTree[maxn<<2];//线段树 void push_up(int rt){ segTree[rt]=max(segTree[rt<<1],segTree[rt<<1|1]); } void build(int rt,int l,int r){ if(l==r){ segTree[rt]=0; return ; } int mid=l+r>>1; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } void update(int rt,int l,int r,int k,int val){ //更新第k位置为val if(l == k && r == k){ segTree[rt]=val;return ; } int mid=l+r>>1; if(k <= mid)update(rt<<1,l,mid,k,val); else update(rt<<1|1,mid+1,r,k,val); push_up(rt); } int query(int rt,int l,int r,int x,int y){ //printf("rt = %d, l = %d, r = %d, x = %d, y = %d\n",rt,l,r,x,y); //int tt;cin>>tt; //查询区间[x,y]的最大值 if(x <= l && r <= y){ return segTree[rt]; } int mid = l+r>>1; int ans=0; if(x<=mid)ans = max(ans,query(rt<<1,l,mid,x,y)); if(y>mid) ans = max(ans,query(rt<<1|1,mid+1,r,x,y)); return ans; } int find(int u,int v){ //查询u-v边中的最大值 int f1 = top[u],f2 = top[v]; int tmp = 0; while(f1 != f2){ if(deep[f1] < deep[f2]){ swap(f1,f2); swap(u,v); } tmp = max(tmp,query(1,1,pos-1,p[f1],p[u]));//在同一条链上的 u = fa[f1]; f1 = top[u]; } if(u == v)return tmp; if(deep[u] > deep[v])swap(u,v); return max(tmp,query(1,1,pos-1,p[son[u]],p[v])); } int e[maxn][3]; int main(){ int T,n; scanf("%d",&T); while(T--){ init(); scanf("%d",&n); for(int i=0;i<n-1;i++){ scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]); addedge(e[i][0],e[i][1]); addedge(e[i][1],e[i][0]); } dfs1(1,0,0); dfs2(1,1); build(1,1,pos-1); for(int i=0;i<n-1;i++){ if(deep[e[i][0]] > deep[e[i][1]]){ swap(e[i][0],e[i][1]); } update(1,1,pos-1,p[e[i][1]],e[i][2]); } char op[34]; int u,v; while(~scanf("%s",op)){ if(op[0]=='D'){ break; } scanf("%d%d",&u,&v); if(op[0]=='Q'){ printf("%d\n",find(u,v)); } else update(1,1,pos-1,p[e[u-1][1]],v); } } return 0; }
相关文章推荐
- UINavigationController先pop再push
- iOS UIButton 自定义图片和文字位置详解
- UIProgressView/UISlider / UISwitch 简单使用
- [leetcode] 187. Repeated DNA Sequences 解题报告
- android rawquery和query的比较
- UItextfield详解 for ios
- 去除UITableView底部多余行及分割线
- 133 - The Dole Queue
- 如何修改Bluetooth link supervision timeout (基于CSR BC4/5)
- UI设计风格的变化
- GradleUserGuide中文版 21)Java插件 22)War插件
- 大数据技术可视化之Hue
- Hibernate利用Query接口进行HQL查询
- UIAlertController中TextField的用法
- UIBezierPath和CAShapeLayer画各种图形
- cf450B. Jzzhu and Sequences
- GradleUserGuide中文版 19)Plugins 20)插件规范 21)Java插件
- UI切图那点事儿
- hdu3434 Sequence Adjustment
- UiAutomator Android 的自动测试框架(UiAutomator 快速调试)