SPOJ 375 QTREE POJ 3237 TREE 树链剖分
2013-08-05 16:47
411 查看
http://wenku.baidu.com/view/8861df38376baf1ffc4fada8
先上一篇论文,我总觉得论文说的不够详细,但是可以理解好多东西。
首先,树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护。
通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中size[v]是以v为根的子树的节点个数,全部由重边组成的路径是重路径,根据论文上的证明,任意一点到根的路径上存在不超过logn条轻边和logn条重路径。
这样我们考虑用数据结构来维护重路径上的查询,轻边直接查询。
通常用来维护的数据结构是线段树。
QTREE是给一棵树,有两种操作,一种是修改一条边的权值,另一种是查询两点路径上的最大值。
POJ3237是在上面两个的基础上再加一个取反操作,就是u到v的路径上所有边的权值乘-1。
下面是POJ3237的代码,拿来先当模板用着了。
【YZ的QTREE树链剖分只用了2.6s但是我的要4.5s,怎么会这么慢……】
先上一篇论文,我总觉得论文说的不够详细,但是可以理解好多东西。
首先,树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护。
通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中size[v]是以v为根的子树的节点个数,全部由重边组成的路径是重路径,根据论文上的证明,任意一点到根的路径上存在不超过logn条轻边和logn条重路径。
这样我们考虑用数据结构来维护重路径上的查询,轻边直接查询。
通常用来维护的数据结构是线段树。
QTREE是给一棵树,有两种操作,一种是修改一条边的权值,另一种是查询两点路径上的最大值。
POJ3237是在上面两个的基础上再加一个取反操作,就是u到v的路径上所有边的权值乘-1。
下面是POJ3237的代码,拿来先当模板用着了。
【YZ的QTREE树链剖分只用了2.6s但是我的要4.5s,怎么会这么慢……】
#include <cstdio> #include <cstring> #include <iostream> using namespace std; #define N 100010 #define IDX(l,r) ((l)+(r) | (l)!=(r)) #define INF (1<<30) int n; int head ,cnt; struct edge { int v,w,next; }e[N<<1]; int dep ,sz ,pnt ,heavy ,rev ,num ; int poi; struct sgt { int mx,mn,lzy; }tree[N<<1]; int find(int x){ return x==pnt[x]?x:pnt[x]=find(pnt[x]); } void addedge(int u,int v,int w) { e[cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt++; } void dfs(int u,int f) { int v,mx=-1; sz[u]=1; heavy[u]=-1; for(int i=head[u];i!=-1;i=e[i].next) if((v=e[i].v)!=f) { dep[v]=dep[u]+1; rev[v]=i^1; dfs(v,u); sz[u]+=sz[v]; if(sz[v]>mx) { mx=sz[v]; heavy[u]=i; } } if(heavy[u]!=-1) pnt[e[heavy[u]].v]=u; } void pushup(int l,int r) { int rt=IDX(l,r),mid=l+r>>1; int rtl=IDX(l,mid),rtr=IDX(mid+1,r); tree[rt].mx=max(tree[rtl].mx,tree[rtr].mx); tree[rt].mn=min(tree[rtl].mn,tree[rtr].mn); } void make(int rt) { int tmp=-tree[rt].mx; tree[rt].mx=-tree[rt].mn; tree[rt].mn=tmp; } void pushdown(int l,int r) { int rt=IDX(l,r),mid=l+r>>1; int rtl=IDX(l,mid),rtr=IDX(mid+1,r); if(tree[rt].lzy) { tree[rtl].lzy^=1; tree[rtr].lzy^=1; make(rtl); make(rtr); tree[rt].lzy=0; } } void build(int l,int r) { int rt=IDX(l,r); tree[rt].mx=-INF; tree[rt].mn=INF; tree[rt].lzy=0; if(l==r) return; int mid=l+r>>1; build(l,mid); build(mid+1,r); } void update(int x,int w,int l,int r) { int rt=IDX(l,r); if(l==r) { tree[rt].mx=tree[rt].mn=w; return; } pushdown(l,r); int mid=l+r>>1; if(x<=mid) update(x,w,l,mid); else update(x,w,mid+1,r); pushup(l,r); } void reverse(int L,int R,int l,int r) { int rt=IDX(l,r); if(L<=l && R>=r) { make(rt); tree[rt].lzy^=1; return; } pushdown(l,r); int mid=l+r>>1; if(L<=mid) reverse(L,R,l,mid); if(R>mid) reverse(L,R,mid+1,r); pushup(l,r); } int query(int L,int R,int l,int r) { int rt=IDX(l,r); if(L<=l && R>=r) return tree[rt].mx; pushdown(l,r); int mid=l+r>>1,ret=-INF; if(L<=mid) ret=max(ret,query(L,R,l,mid)); if(R>mid) ret=max(ret,query(L,R,mid+1,r)); return ret; } int queryuv(int u,int lca) { int ans=-INF; while (u!=lca) { int ed=rev[u]; if(num[ed]==-1) { ans=max(ans,e[ed].w); u=e[ed].v; } else { int p=pnt[u]; if(dep[p]<dep[lca]) p=lca; ans=max(ans,query(num[ed],num[heavy[p]],1,n-1)); u=p; } } return ans; } void init() { build(1,n-1); memset(num,-1,sizeof(num)); dep[1]=poi=0; for(int i=1;i<=n;++i) pnt[i]=i; dfs(1,0); for(int i=1;i<=n;++i) if(heavy[i]==-1) { int pos=i; while (pos!=1 && e[heavy[e[rev[pos]].v]].v==pos) { int t=rev[pos]; num[t]=num[t^1]=++poi; update(num[t],e[t].w,1,n-1); pos=e[t].v; } } } void change(int edge,int val) { if(num[edge]==-1) e[edge].w=e[edge^1].w=val; else update(num[edge],val,1,n-1); } void NGT(int u,int lca) { while (u!=lca) { int ed=rev[u]; if(num[ed]==-1) { e[ed].w=e[ed^1].w=-e[ed].w; u=e[ed].v; } else { int p=pnt[u]; if(dep[p]<dep[lca]) p=lca; reverse(num[ed],num[heavy[p]],1,n-1); u=p; } } } int lca(int u,int v) { while (1) { int a=find(u),b=find(v); if(a==b) return dep[u]<dep[v]?u:v; else if(dep[a]>=dep[b]) u=e[rev[a]].v; else v=e[rev[b]].v; } } int solve(int u,int v) { int p=lca(u,v); return max(queryuv(u,p),queryuv(v,p)); } void _negate(int u,int v) { int p=lca(u,v); NGT(u,p); NGT(v,p); } int main () { int tt; int u,v,w; char s[15]; scanf("%d",&tt); while (tt--) { cnt=0; memset(head,-1,sizeof(head)); scanf("%d",&n); for(int i=1;i<n;++i) { scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } init(); while (scanf("%s",s)) { if(s[0]=='D') break; if(s[0]=='Q') { scanf("%d%d",&u,&v); printf("%d\n",solve(u,v)); } else if(s[0]=='C') { scanf("%d%d",&u,&w); change((u-1)<<1,w); } else { scanf("%d%d",&u,&v); _negate(u,v); } } } return 0; }
相关文章推荐
- 【SPOJ 375】 【POJ 3237】 375. Query on a tree 树链剖分
- spoj 375 Query on a tree 树链剖分
- spoj 375 Query on a tree(树链剖分,线段树)
- SPOJ 375 Query on a tree(树链剖分)(QTREE)
- spoj375 Query on a tree(树链剖分 边权 入门题)
- 【树链剖分】SPOJ 375 Query on a tree 裸题
- spoj375 Query on a tree(树链剖分)
- SPOJ 375 Query on a tree(初学树链剖分)
- spoj 375 QTREE - Query on a tree(树链剖分,边权)
- spoj 375 QTREE - Query on a tree 树链剖分 LCT 动态树
- SPOJ 375 QTREE系列-Query on a tree (树链剖分)
- SPOJ 375 Query on a tree(树链剖分)
- 【SPOJ375】Query on a tree-树链剖分
- SPOJ 题目 375 QTREE - Query on a tree(树链剖分)
- spoj 375 Query on a tree 树链剖分
- kyeremal-spoj375-Query on a tree-树链剖分
- 【树链剖分模板】【SPOJ 375】 Query on a tree
- SPOJ 375 QTREE Query on a tree 树链剖分水题
- SPOJ 375 树链剖分 QTREE - Query on a tree
- 【spoj375】Query on a tree【树链剖分】【或者动态树,那样常数就完了T_T】