您的位置:首页 > 编程语言 > Qt开发

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,怎么会这么慢……】

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: