题目 链接:http://poj.org/problem?id=2763

Language:Default

Housewife Wind

Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions: 16100   Accepted: 4388

Description

After their royal wedding, Jiajia and Wind hid away in XX Village, to enjoy their ordinary happy life. People in XX Village lived in beautiful huts. There are some pairs of huts connected by bidirectional roads. We say that huts in the same pair directly connected. XX Village is so special that we can reach any other huts starting from an arbitrary hut. If each road cannot be walked along twice, then the route between every pair is unique.

Since Jiajia earned enough money, Wind became a housewife. Their children loved to go to other kids, then make a simple call to Wind: 'Mummy, take me home!'

At different times, the time needed to walk along a road may be different. For example, Wind takes 5 minutes on a road normally, but may take 10 minutes if there is a lovely little dog to play with, or take 3 minutes if there is some unknown strange smell surrounding the road.

Wind loves her children, so she would like to tell her children the exact time she will spend on the roads. Can you help her?

Input

The first line contains three integers n, q, s. There are n huts in XX Village, q messages to process, and Wind is currently in hut s. n < 100001 , q < 100001.

The following n-1 lines each contains three integers a, b and w. That means there is a road directly connecting hut a and b, time required is w. 1<=w<= 10000.

The following q lines each is one of the following two types:

Message A: 0 u 
A kid in hut u calls Wind. She should go to hut u from her current position. 
Message B: 1 i w 
The time required for i-th road is changed to w. Note that the time change will not happen when Wind is on her way. The changed can only happen when Wind is staying somewhere, waiting to take the next kid.

Output

For each message A, print an integer X, the time required to take the next child.

Sample Input

3 3 1
1 2 1
2 3 2
0 2
1 2 3
0 3

Sample Output

1
3

Source

POJ Monthly--2006.02.26,zgl & twb

题意:给出一个树,q个询问,s为起点,0 u 询问由目前所在点到u点的距离,1 k val代表修改第k条边的权值为val

解法一:

初学LCA,刚入门的第一题,题目lca+树状数组的思想还是比较好的,记录一下

ps:poj此题G++超时,C++ AC 可能卡STL,建议换成链向星

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=2e5+100;
struct node
{int to,val,id;node(int a,int b,int c):to(a),val(b),id(c){}
};
vector<node> v[maxn];
int fa[maxn][20],dis[maxn],depth[maxn];
int c[maxn],id[maxn],l[maxn],r[maxn],num,cc[maxn];
int n,s,q;
//lca部分
void dfs(int u)
{l[u]=++num;//dfs序 将树形结构转换成线性结构for(int i=0;i<v[u].size();i++){node te=v[u][i];if(te.to==fa[u][0]) continue;fa[te.to][0]=u;dis[te.to]=dis[u]+te.val;depth[te.to]=depth[u]+1;id[te.id]=te.to;//id[i] 代表第i条边对应的离根节点远的节点dfs(te.to);}r[u]=num;
}
void init()
{for(int j=1;(1<<j)<=n;j++){for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];}
}
int lca(int a,int b)
{if(depth[a]>depth[b]) swap(a,b);int f=depth[b]-depth[a];for(int i=0;(1<<i)<=f;i++){if((1<<i)&f) b=fa[b][i];}if(a==b) return a;for(int i=19;i>=0;i--){if(fa[a][i]!=fa[b][i]){a=fa[a][i];b=fa[b][i];}}return fa[a][0];
}
//树状数组部分
int lowerbit(int x)
{return x&(-x);
}
void add(int pos,int x)
{while(pos<=n){cc[pos]+=x;pos+=lowerbit(pos);}
}
int sum(int pos)
{int ans=0;while(pos>0){ans+=cc[pos];pos-=lowerbit(pos);} return ans;
}int main()
{while(~scanf("%d%d%d",&n,&q,&s)){memset(v,0,sizeof(v));memset(c,0,sizeof(c));memset(cc,0,sizeof(cc));num=0;for(int i=1;i<n;i++){int a,b,cc;scanf("%d%d%d",&a,&b,&cc);v[a].push_back(node(b,cc,i));v[b].push_back(node(a,cc,i));c[i]=cc;}fa[1][0]=0,dis[1]=0,depth[1]=0;dfs(1);init();for(int i=1;i<n;i++)//对图中原有的节点进行加边操作 add(l[id[i]],c[i]),add(r[id[i]]+1,-c[i]);while(q--){  int op;scanf("%d",&op);if(op==0){int u;scanf("%d",&u);//用dfs序代替节点 使得节点出现顺序 改变之前节点以后节点相应受到影响 printf("%d\n",sum(l[u])+sum(l[s])-2*sum(l[lca(s,u)]));      s=u;                                                 }else if(op==1){int k,va;scanf("%d%d",&k,&va);int tmp=c[k];c[k]=va;add(l[id[k]], va-tmp); add(r[id[k]]+1, tmp-va);//差分区间简单运用}}}return 0;} 

题意没有太多坑,自己跑下样例应该就能理解了

给组样例:

5 5 1
1 2 3
2 3 4
1 4 2
2 5 1
0 3
1 4 3
1 1 4
0 4
0 5

结果:

7
10
9

总结:题目利用时间戳来代替节点,这样每个节点在树中遍历的顺序体现出来,如果改变v u两节点的对应边的权值,那么到以u为根的子节点长度(根节点到子节点长度)均受到改变(包括u,默认u离根节点远),因此对l[i] 加减 对r[i] 相反操作可以只影响到以u为根节点的子节点的权值,通过求前缀和来计算根节点到此节点的长度(差分区间简单运用,点修改,区间查询用树状数组),再通过lca可以简单求出两点的最短路了

解法二:

树链剖分的模板题,边权的单点修改,以及区间查询

见代码注释:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=2e5+100;
int fa[maxn],top[maxn],depth[maxn],l[maxn],size[maxn],son[maxn];
int tt;
int sum[maxn<<2];
vector<int> v[maxn];
int n,q,s;
int cnt, head[maxn];
struct Edge {int to, next;
}edge[maxn];
void add_edge(int f,int t)
{edge[cnt].to=t;edge[cnt].next=head[f];head[f]=cnt++;
}
//预处理部分
void dfs1(int u,int pre)
{size[u]=1;for(int i = head[u]; ~i; i= edge[i].next) {int te=edge[i].to;if(te==pre ) continue;depth[te]=depth[u]+1;dfs1(te,u);fa[te]=u;size[u]+=size[te]; if(son[u]==0||size[te]>size[son[u]])son[u]=te;}
}
void dfs2(int u,int ft)
{l[u]=++tt;top[u]=ft;if(son[u]) dfs2(son[u],top[u]);for(int i = head[u]; ~i; i = edge[i].next) {int te=edge[i].to;if(te==fa[u]||te==son[u]) continue;dfs2(te,te);}
}
struct node
{int f,t,val;
}e[maxn];
//线段树部分
void update(int p,int val,int l,int r,int rt)
{if(l==r){sum[rt]=val;return ;}int m=(l+r)>>1;if(p<=m) update(p,val,l,m,rt<<1);else update(p,val,m+1,r,rt<<1|1);sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt)
{if(L<=l&&r<=R){return sum[rt];}int m=(l+r)>>1;int ans=0;if(L<=m) ans+=query(L,R,l,m,rt<<1);if(R>m) ans+=query(L,R,m+1,r,rt<<1|1);return ans;
}
//熟练剖分核心
void change(int k,int val){int f=e[k].f,t=e[k].t;if(depth[f]>depth[t]) swap(f,t);//单点更新 update(l[t],val,1,n,1);
}
int get(int x,int y)
{int fx=top[x],fy=top[y];int ans=0;while(fx!=fy){if(depth[fx]>depth[fy]){swap(fx,fy);swap(x,y);}ans+=query(l[fy],l[y],1,n,1);y=fa[fy];fy=top[y];}if(x==y) return ans;if(depth[x]>depth[y]) swap(x,y);ans+=query(l[son[x]],l[y],1,n,1);//边权 选取x的重儿子 因为l[x]代表x节点和其父节点的变 直接用x会包括与父节点的边 return ans;
}
int main()
{scanf("%d%d%d",&n,&q,&s);memset(head,-1,sizeof(head));cnt=0;tt=0;for(int i=1;i<n;i++){int f,t,val;scanf("%d%d%d",&f,&t,&val);e[i].f=f;e[i].t=t;e[i].val=val;add_edge(f,t);add_edge(t,f);}fa[1]=0;depth[1]=0;dfs1(1,0);dfs2(1,1);for(int i=1;i<n;i++){int f=e[i].f,t=e[i].t;int val=e[i].val;if(depth[f]>depth[t]) swap(f,t);update(l[t],val,1,n,1);}while(q--){int op;scanf("%d",&op);if(op==0){int t;scanf("%d",&t);printf("%d\n",get(s,t)); s=t;}else{int k,val;scanf("%d%d",&k,&val);change(k,val); }}return 0;} 

一点思考:树链剖分很好的解决了树上的区间修改和区间查询问题,本题单点修改用lca+BIT也可以很好的解决

注意:poj卡vector

Housewife Wind POJ - 2763 倍增LCA+树状数组 或 树链剖分+线段树相关推荐

  1. HDU - 6183 Color it(动态开点线段树/树状数组套动态开点线段树)

    题目链接:点击查看 题目大意:给出一个二维平面坐标系,需要完成四种操作: 0:删除所有点 1 xycx\ y\ cx y c:在点 (x,y)(x,y)(x,y) 处添加颜色 ccc 2 xy1y2x ...

  2. P3157 动态逆序对 ,树状数组套动态开点线段树

    题目 洛谷题目链接 题解 在求整体的逆序对的数量时,很好办,直接用树状数组处理即可,不过在这时,我们还需要处理出一个数组pa[]pa[]pa[],其中pa[i]pa[i]pa[i]代表在区间[1,i) ...

  3. 蓝书4.1-4.4 树状数组、RMQ问题、线段树、倍增求LCA

    这章的数据结构题很真实 T1 排队 bzoj 1699 题目大意: 求静态一些区间的最大值-最小值 思路: ST表裸题 1 #include<iostream> 2 #include< ...

  4. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  5. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  6. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  7. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  8. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  9. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

最新文章

  1. chromedp网络监听_动态爬虫三:监听网络事件 + 监听js事件
  2. dos删除文件与文件夹
  3. 巧用Graphviz和pvtrace等工具可视化C函数调用
  4. Shell中I/O重定向的用法笔记
  5. java拦截器项目应用_使用拦截器分析Java EE应用程序的性能下降/提高
  6. C/C++中volatile关键字的作用
  7. Java讲课笔记10:类的封装
  8. 如何使用模板生成多个页面_Divi不再只是页面构建器。 使用主题生成器,可以完全设计整个网站。...
  9. android 用户中心布局,android用户中心头像选择功能的方法实现-Go语言中文社区
  10. django css,Django表单中的CSS样式
  11. Lua 中写 C 扩展库时用到的一些技巧
  12. 引用父类成员的关键字是java_Java 中对父类成员访问用的关键字是 ,而引用当前对象的关键字是 。_学小易找答案...
  13. 浙江大学-西湖大学联合培养博士生
  14. logistic回归分析优点_干货——检验人最常用的统计学分析方法梳理(二)
  15. 荣耀电视鸿蒙安装第三方软件,荣耀电视如何安装第三方应用?当贝市场几招搞定!...
  16. CATIA二次开发(一):CAA简介
  17. GitHub上史上最全的iOS开源项目分类汇总
  18. 一步一步学Silverlight 2系列(30):使用Transform实现更炫的效果(下)
  19. 微信企业号开发常用工具类总结(一)
  20. python-模块使用方法

热门文章

  1. 3C认证和质检报告的区别
  2. 基于Java毕业设计疫情状态下的图书馆座位预约系统源码+系统+mysql+lw文档+部署软件
  3. 选择域名的基本准则以及注意事项
  4. Microland被Everest Group评为主要竞争者和明星企业
  5. [转载]使用Java编写Palm OS程序的解决方案
  6. 制作集成SATA驱动的xp安装盘
  7. 缺少msvcr100.dll的解决方法
  8. Neutrino追问AMA第16期|everiToken程希冀:通过安全合约技术让用户一键发通证
  9. 17. 监测 web 网站的可用性
  10. Servlet笔记十(文件上传和下载)