简单题III
Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^
题目描述
RE最近在写一款名叫《我不要娶公主》的RPG游戏(听名字就知道这货单身久
了准备FFF),既然是RPG类游戏那么少不了的就是小地图的自动寻路。耿直的RE决定暴力掉这个
算法。显然是不行的。所以,这便求到我们这群人。在这个RPG的地图上共有N个复活点,N-1条路
,链接整张的地图,保证每两点可达,已知每一条路的长度,战斗就发生在各个复活点和通往复
活点的路上。玩家之间的战斗可以改变道路的地形,这便会改变每一条路的长度,那么问题来了
。我们如何让玩家得知自己所在的复活点距离自己的目的地多远。
输入
多组输入。每组首先输入两个整数n,m。n为复活点数(n<100001),m为操作数(m<100001)。
随后按照书序输入n-1组三个整数u,v,w,表示u复活点与v复活点之间的路程为w。(1<=w<=10000),
最后输入m步操作,每一步操作首先输入一个数字k((k=0||k=1)
最后输入m步操作,每一步操作首先输入一个数字k((k=0||k=1)
当k = 0时,输入两个数x,y,表示查询从复活点x到复活点y的总路程。
当k = 1时,输入两个数x,y,表示玩家的战斗导致第x条路的长度变成了y。
输出
输出玩家查询的从x复活点到y复活点的距离。
示例输入
3 3 1 2 1 2 3 2 0 1 2 1 2 3 0 2 3
示例输出
1 3
可算是搞出来了一道树剖的题。首先在这里鸣谢JinZeyu金巨巨QAQQAsQ巨耐心给窝讲解,实话说,我看一天论文都赶不上这么几分钟的讲解!论文太泛了,许多明白的地方讲的很细,我个人不太懂的地方又一笔带过,所以一直不太又耐心看整篇的论文(也是个缺点
扯远了,自家出的题,当时用LCA水过去了,也是数据较弱。赛后黑腹地跑了组数据把所有LCA给卡掉了(就在刚刚~。~
树链剖分真心是个好东西(虽然到现在我还只会这么裸着用。。
第一遍dfs,找出所有点的深度、父亲、重儿子、子树节点数
第二遍dfs,贪心地往重儿子方向跑(保证每条重链上的点dfs序连续,也是为了区间修改和查询做准备)标记每个点的dfs序,同时标记每个点所在重链的链顶。
至于上面的重儿子 重链。。百度吧=.=
突然感觉会树剖的看我刚才说的就是废话,不会树剖的看就是天书=.=(好欠揍。。。
总之这么跑完后用线段树或树状数组之类的数据结构维护一下区间,然后区间更新或查询就好,。
说了一通废话,上代码吧。。
#include <iostream> #include <cmath> #include <vector> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <stack> #include <list> #include <algorithm> #include <map> #include <set> #define LL long long #define Pr pair<int,int> #define fread() freopen("data2.in","r",stdin) #define fwrite() freopen("data2.out","w",stdout) using namespace std; const int INF = 0x3f3f3f3f; const int msz = 10000; const int mod = 1e9+7; const double eps = 1e-8; struct Edge { int v,w,next; }; int head[233333]; Edge eg[233333]; //点深度 链顶 子树节点数 重儿子 父节点 代表的边权 访问编号 int dep[233333],top[233333],siz[233333],son[233333],fa[233333],val[233333],tid[233333]; int bit[444444]; int n,m,tim; void dfs1(int u,int pre,int d) { //父亲 fa[u] = pre; //深度 dep[u] = d; //子树点个数 siz[u] = 1; //重儿子 son[u] = u; int tmp = -1; int v,w; for(int i = head[u]; ~i; i = eg[i].next) { v = eg[i].v; if(v == pre) continue; dfs1(v,u,d+1); siz[u] += siz[v]; if(siz[v] > tmp) { tmp = siz[v]; son[u] = v; } } } void dfs2(int u,int d) { top[u] = d; tid[u] = ++tim; if(son[u] == u) return; //贪心先找重儿子 dfs2(son[u],d); int v; for(int i = head[u]; ~i; i = eg[i].next) { v = eg[i].v; if(v != fa[u] && v != son[u]) dfs2(v,v); val[tid[v]] = eg[i].w; } } void build(int root,int l,int r) { if(l == r) { bit[root] = val[l]; return; } int mid = (l+r)>>1; build(root<<1,l,mid); build(root<<1|1,mid+1,r); bit[root] = bit[root<<1]+bit[root<<1|1]; } void update(int root,int l,int r,int ll,int d) { if(l == r) { bit[root] = d; return; } int mid = (l+r)>>1; if(mid >= ll) update(root<<1,l,mid,ll,d); else update(root<<1|1,mid+1,r,ll,d); bit[root] = bit[root<<1]+bit[root<<1|1]; } int query(int root,int l,int r,int ll,int rr) { if(l == ll && r == rr) { return bit[root]; } int mid = (l+r)>>1; if(mid >= rr) return query(root<<1,l,mid,ll,rr); else if(mid+1 <= ll) return query(root<<1|1,mid+1,r,ll,rr); else return query(root<<1,l,mid,ll,mid)+query(root<<1|1,mid+1,r,mid+1,rr); } void init() { tim = 0; dfs1(1,1,1); val[1] = 0; dfs2(1,1); build(1,1,tim); } int main() { fread(); fwrite(); int u,v,w,k,x,y; while(~scanf("%d%d",&n,&m)) { memset(head,-1,sizeof(head)); int tp = 2; for(int i = 1; i < n; ++i) { scanf("%d%d%d",&u,&v,&w); eg[tp].v = v; eg[tp].w = w; eg[tp].next = head[u]; head[u] = tp++; eg[tp].v = u; eg[tp].w = w; eg[tp].next = head[v]; head[v] = tp++; } init(); while(m--) { scanf("%d%d%d",&k,&x,&y); if(k == 1) { u = eg[x<<1].v; v = eg[x<<1|1].v; val[max(tid[u],tid[v])] = y; update(1,1,n,max(tid[u],tid[v]),y); } else { int ans = 0; while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x,y); ans += query(1,1,n,tid[top[x]],tid[x]); x = fa[top[x]]; } if(tid[x] < tid[y]) swap(x,y); ans += query(1,1,n,tid[y],tid[x])-val[tid[y]]; printf("%d\n",ans); } } } return 0; }