简单题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;
}