FZU 2082 求樹上任意點間距離 邊權轉為點權 樹鏈剖分
阿新 • • 發佈:2019-02-09
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 __int64 struct 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); //建立虛擬根節點1 updata(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 99 7 1 1 1 2 2 1 3 3 2 6 4 2 4 5 3 5 6 1 6 3 1 2 5 1 4 5 1 1 5 1 7 5 0 1 100 1 7 5 0 6 100 1 3 5 1 5 3 1 5 4 */