您的位置:首页 > 产品设计 > UI/UE

树链剖分 spoj 375 Query on a tree(剖分入门)

2016-05-05 14:42 513 查看
题目链接

树链剖分学习

树链剖分并不是一个复杂的算法或者数据结构,只是能把一棵树拆成链来处理而已,换一种说法,树链剖分只是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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: