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

SPOJ375 Query on a tree

2016-09-21 11:17 239 查看
题目链接:点击打开链接

题意:有一棵n(n<=10000)个节点的树,每条边有一个权值wi.现有两种操作:1.改变第i条边的权值,2.询问a到b路径上最大的边权

题解:树链剖分入门题。学习树链剖分请点这里

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long LL;

const int N=10000+10;
const int E=20000+10;

int n;
int d
,Fa
,Size
,Top
,p
,Son
;
int T[N<<2];
int pos;
int Edge
[3];
vector<int>V
;

void dfs1(int u,int Pre,int Dep)//第一遍dfs求Fa,d,Size,Son
{
d[u]=Dep;
Fa[u]=Pre;
Size[u]=1;
for (int i=0;i<int(V[u].size());i++){
int v=V[u][i];
if (v!=Pre){
dfs1(v,u,Dep+1);
Size[u]+=Size[v];
if (Son[u]==-1 || Size[v]>Size[Son[u]]) Son[u]=v;
}
}
}
void dfs2(int u,int sp)//top和p
{
Top[u]=sp;
p[u]=pos++;
if (Son[u]==-1) return ;
dfs2(Son[u],sp);
for (int i=0;i<int(V[u].size());i++){
int v=V[u][i];
if (Fa[u]!=v && Son[u]!=v) dfs2(v,v);
}
}
void Build(int p,int L,int R)
{
T[p]=0;
if (L==R)return ;
int mid=(L+R)>>1;
Build(p<<1,L,mid);
Build((p<<1)^1,mid+1,R);
}
void Insert(int p,int L,int R,int pos,int v)
{
if (L==R){
T[p]=v;return ;
}
int mid=(L+R)>>1;
if (pos<=mid) Insert(p+p,L,mid,pos,v);
else Insert(p+p+1,mid+1,R,pos,v);
T[p]=max(T[p+p],T[p+p+1]);
}
int Find(int p,int L,int R,int l,int r)
{
if (L==l && R==r)return T[p];
int mid=(L+R)>>1;
if (r<=mid)return Find(p+p,L,mid,l,r);
else if (mid<l)return Find(p+p+1,mid+1,R,l,r);
else return max(Find(p+p,L,mid,l,mid),Find(p+p+1,mid+1,R,mid+1,r));
}
int Query(int u,int v)
{
int f1=Top[u],f2=Top[v];
int tmp=0;
while (f1!=f2){
if (d[f1]<d[f2]){
swap(f1,f2);swap(u,v);
}
tmp=max(tmp,Find(1,1,pos,p[Top[u]],p[u]));
u=Fa[f1];f1=Top[u];
}
if (u==v)return tmp;
if (d[u]<d[v])swap(u,v);
return max(tmp,Find(1,1,pos,p[Son[v]],p[u]));
}
void work()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)V[i].clear();
for (int i=1;i<n;i++){
scanf("%d%d%d",&Edge[i][0],&Edge[i][1],&Edge[i][2]);
V[Edge[i][0]].push_back(Edge[i][1]);
V[Edge[i][1]].push_back(Edge[i][0]);
}
pos=1;
for (int i=1;i<=n;i++)Son[i]=-1;
dfs1(1,0,0);
dfs2(1,1);
Build(1,1,pos);
for (int i=1;i<n;i++){
if (d[Edge[i][0]]<d[Edge[i][1]])
swap(Edge[i][0],Edge[i][1]);
Insert(1,1,pos,p[Edge[i][0]],Edge[i][2]);
}
char str[100];
while (scanf("%s",str)!=EOF && str[0]!='D'){
int x,y;scanf("%d%d",&x,&y);
if (str[0]=='Q'){
printf("%d\n",Query(x,y));
}else Insert(1,1,pos,p[Edge[x][0]],y);
}
}
int main()
{
//freopen("1.txt","r",stdin);
int Case;scanf("%d",&Case);
while (Case--)work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  SPOJ 树链剖分