poj2763 Housewife Wind LCA
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj2763 Housewife Wind LCA相关的知识,希望对你有一定的参考价值。
题目链接:
http://poj.org/problem?id=2763
题意:
一个无根树,给出主角一开始所在的位置S,然后下面q个操作,操作包括查询和修改操作,对于查询操作就是当前主角的位置到目的点的距离是多少,然后主角去到那里之后就在那里等待,下次查询的时候那里就是新的起点(所以sample中第二次查询为什么是3)。修改是修改第k条边的权值,边的编号就是输入的顺序。
思路:
求树上两点之间的距离,ans=dis[u]+dis[v]-dis[LCA(u,v)]*2;
求LCA这里是用的倍增的思想, 先让两个点跳到同一深度,然后两个点再同时往上跳,先跳大步。
还有别的方法求LCA,http://www.cnblogs.com/scau20110726/archive/2013/06/14/3135095.html 这个人的LCA挺好的【离线RMQ】。我觉得还是在线倍增比较好理解
对于修改,修改一条边,暴力更新dis这个数组,数据水,这样可以通过。
对于树链剖分的做法 蒟蒻不会
代码:
代码一:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; #define MS(a) memset(a,0,sizeof(a)) #define MP make_pair #define PB push_back const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();} while(ch>=\'0\'&&ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();} return x*f; } ////////////////////////////////////////////////////////////////////////// const int maxn = 1e5+10; struct node{ int u,v,w,next; }e[maxn*2]; int tot,dp[maxn][25],dep[maxn],head[maxn],dis[maxn]; void add(int u,int v,int w,int &k){ e[k].u=u; e[k].v=v; e[k].w=w; e[k].next=head[u]; head[u]=k++; swap(u,v); e[k].u=u; e[k].v=v; e[k].w=w; e[k].next=head[u]; head[u]=k++; } void dfs(int u,int f){ dep[u] = dep[f]+1; dp[u][0] = f; for(int i=head[u]; i!=-1; i=e[i].next){ int v = e[i].v, w = e[i].w; if(v == f) continue; dis[v] = dis[u]+w; dfs(v,u); } } int LCA(int x,int y){ if(dep[x] < dep[y]) swap(x,y); for(int i=20; i>=0; i--) if(dep[dp[x][i]]>=dep[y]) x = dp[x][i]; if(x == y) return x; for(int i=20; i>=0; i--) if(dep[dp[x][i]]==dep[dp[y][i]] && dp[x][i]!=dp[y][i]) x = dp[x][i], y = dp[y][i]; return dp[x][0]; } void change(int u,int f,int val){ dis[u] += val; for(int i=head[u]; i!=-1; i=e[i].next){ if(f == e[i].v) continue; change(e[i].v,u,val); } } int main(){ int n,q,s; while(cin>>n>>q>>s){ tot = 0; memset(head,-1,sizeof(head)); for(int i=1; i<n; i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w,tot); } dfs(1,0); for(int i=1; i<=20; i++) for(int j=1; j<=n; j++) dp[j][i] = dp[dp[j][i-1]][i-1]; while(q--){ int op = read(); if(op == 0){ int v = read(); int ans = dis[s]+dis[v]-2*dis[LCA(s,v)]; s = v; cout << ans << endl; }else{ int p,y; scanf("%d%d",&p,&y); p = (p-1)*2; int u = e[p].u, v = e[p].v, w = e[p].w; int t1 = dep[u]<dep[v] ? v:u; int t2 = dep[u]<dep[v] ? u:v; e[p].w = e[p^1].w = y; change(t1,t2,y-w); } } } return 0; }
代码二:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; #define MS(a) memset(a,0,sizeof(a)) #define MP make_pair #define PB push_back const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; inline ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<\'0\'||ch>\'9\'){if(ch==\'-\')f=-1;ch=getchar();} while(ch>=\'0\'&&ch<=\'9\'){x=x*10+ch-\'0\';ch=getchar();} return x*f; } ////////////////////////////////////////////////////////////////////////// const int maxn = 1e5+10; int n,q,s,tot; int head[maxn]; struct edge{ int u,v,w,next; }e[maxn*2]; void add(int u,int v,int w,int &k){ e[k].u=u; e[k].v=v; e[k].w=w; e[k].next=head[u]; head[u]=k++; swap(u,v); e[k].u=u; e[k].v=v; e[k].w=w; e[k].next=head[u]; head[u]=k++; } int ver[maxn*2],R[maxn*2],fir[maxn],_pow[25],dis[maxn],dp[maxn*2][25],dep[maxn]; bool vis[maxn]; void dfs(int u,int d){ vis[u]=true; ver[++tot]=u, R[tot]=d, fir[u]=tot, dep[u]=d; for(int i=head[u]; i!=-1; i=e[i].next){ int v=e[i].v,w=e[i].w; if(vis[v]) continue; dis[v] = dis[u]+w; dfs(v,d+1); ver[++tot]=u,R[tot]=d; } } void ST(int len){ int k = (int)(log(len*1.0)/log(2.0)); for(int i=0; i<=len; i++) dp[i][0] = i; for(int j=1; j<=k; j++){ for(int i=1; i+(1<<j)-1<=len; i++){ int a = dp[i][j-1], b = dp[i+_pow[j-1]][j-1]; if(R[a] < R[b]) dp[i][j] = a; else dp[i][j] = b; } } } int RMQ(int x,int y){ int k = (int)(log((y-x+1)*1.0)/log(2.0)); int a = dp[x][k], b = dp[y-_pow[k]+1][k]; if(R[a] < R[b]) return a; else return b; } int LCA(int x,int y){ int a = fir[x], b = fir[y]; if(a > b) swap(a,b); int res = RMQ(a,b); return ver[res]; } void change(int u,int f,int x){ dis[u] += x; for(int i=head[u]; i!=-1; i=e[i].next){ int v = e[i].v; if(v == f) continue; change(v,u,x); } } int main(){ for(int i=0; i<25; i++) _pow[i] = (1<<i); while(cin>>n>>q>>s){ tot = 0; memset(head,-1,sizeof(head)); for(int i=1; i<n; i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w,tot); } tot = 0; MS(dis); MS(vis); dfs(1,1); ST(tot); while(q--){ int op = read(); if(op == 0){ int v = read(); int ans = dis[s]+dis[v]-2*dis[LCA(s,v)]; s = v; cout << ans << endl; }else{ int x,y; scanf("%d%d",&x,&y); int t = (x-1)*2; int u = e[t].u, v = e[t].v, w = e[t].w; int t1 = dep[u]>dep[v] ? u:v; int t2 = dep[u]>dep[v] ? v:u; e[t].w = e[t^1].w = y; change(t1,t2,y-w); } } } return 0; }
以上是关于poj2763 Housewife Wind LCA的主要内容,如果未能解决你的问题,请参考以下文章
LCA+线段树/树状数组 POJ2763 Housewife Wind
POJ 2763 Housewife Wind(树链剖分)(线段树单点修改)
POJ 2763 Housewife Wind(DFS序+LCA+树状数组)