FZU 2082 求树上任意点间距离 边权转为点权 树链剖分

来源:互联网 发布:windows程序视频 编辑:程序博客网 时间:2024/05/22 03:35

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2082

wushen博客:wuyiqi

思路:

边权转点权:

由于线段树中的点是节点,则把题目给的边权值作为 边一端 距离根更远的节点的点权值。

直接设置根权值为0 这样不会影响题意。

因为求的的是两点间所有的点权和,所以要减去 LCA(u,v),因为这个点所代表的边是没有在路径上的。

#include<stdio.h>#include<iostream>#include<string.h>using namespace std;#define N 50050#define L(x) (x<<1)#define R(x) (x<<1|1)#define Mid(x,y) ((x+y)>>1)#define ll __int64struct Edge{ll from, to, dis,nex;bool yes;}edge[N<<1];ll head[N], edgenum;ll dis[N];void addedge(ll u, ll v, ll d){Edge E={u,v,d,head[u],false};edge[edgenum] = E;head[u] = edgenum++;}ll son[N];ll top[N];ll fp[N];ll p[N];ll siz[N];ll dep[N];ll fa[N];ll tree_id;void dfs(ll u, ll father, ll deep){fa[u] = father; dep[u] = deep;siz[u] = 1;for(ll i = head[u]; ~i; i = edge[i].nex){ll v = edge[i].to; if(v == father)continue;dfs(v, u, deep+1);siz[u] += siz[v];if(son[u] == -1 || siz[son[u]]<siz[v])son[u] = v;dis[v] = edge[i].dis;edge[i].yes = true;}}void getpos(ll u, ll toppos){p[u] = tree_id++; fp[p[u]] = u;top[u] = toppos;if(son[u] == -1)return;if(u==0)getpos(son[u],son[u]);else getpos(son[u], toppos);for(int i = head[u]; ~i; i = edge[i].nex){int v = edge[i].to; if(v == fa[u] || v == son[u])continue;getpos(v,v);}}struct node{ll l, r;ll sum;}tree[N*8];void updata_up(ll id){tree[id].sum = tree[L(id)].sum+tree[R(id)].sum;}void build(ll l, ll r, ll id){tree[id].l = l, tree[id].r = r;tree[id].sum = 0;if(l == r)return ;int mid = Mid(l,r);build(l,mid,L(id)), build(mid+1,r,R(id));}void updata(ll pos, ll val, ll id){if(tree[id].l == tree[id].r){tree[id].sum = val;return;}ll mid = Mid(tree[id].l,tree[id].r);if(pos <= mid)updata(pos, val, L(id));else updata(pos, val, R(id));updata_up(id);}ll query(ll l, ll r, ll id){if(l <= tree[id].l && tree[id].r <= r)return tree[id].sum;ll mid = Mid(tree[id].l, tree[id].r);ll ans = 0;if(l <= mid)ans+=query(l,r,L(id));if(r >  mid)ans+=query(l,r,R(id));return ans;}ll Query(ll x,ll y){ //让x在y下面ll f1 = top[x], f2 = top[y];ll ans = 0;while(f1 != f2){if(dep[f1]<dep[f2])swap(f1,f2),swap(x,y);ans += query(p[f1],p[x],1);x = fa[f1];f1 = top[x];}if(dep[x] > dep[y])swap(x,y);return ans + query(p[x],p[y],1) - query(p[x],p[x],1);;}void change(ll pos, ll val){Edge &E = edge[pos<<1]; if(E.yes == false) E = edge[pos<<1|1];E.dis = val;updata(p[E.to], val, 1);}ll n, m;void init(){memset(head, -1, sizeof(head)), edgenum = 0;memset(son, -1, sizeof(son));tree_id = 1;}int main(){ll i, j, u, v, d;while(~scanf("%I64d %I64d",&n,&m)){init();for(i = 1; i < n; i++) {scanf("%I64d %I64d %I64d",&u,&v,&d);addedge(u,v,d);addedge(v,u,d);}dfs(1,1,0);getpos(1,1);build(1,n,1); //建立虚拟根节点1updata(p[1],0,1);for(i = 2; i <= n; i++)updata(p[i],dis[i],1);while(m--){scanf("%I64d %I64d %I64d",&d,&u,&v);if(d == 0)change(u-1,v);else printf("%I64d\n",Query(u,v));}}return 0;}/*7 997 1 11 2 21 3 32 6 42 4 53 5 61 6 31 2 51 4 51 1 51 7 50 1 1001 7 50 6 1001 3 51 5 31 5 4*/


0 0