foj 2082 树链剖分 第2天

擦,没啥好说的,这个模板至少得打10遍。。纪念自己成功的打错了。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL int
#define lson id << 1
#define rson id << 1|1
const  LL M = 100008;
LL ti[M],top[M],siz[M],son[M],father[M],tp,idx,dep[M];
struct Linetree{
    LL sum,l,r,mark;
    LL mid(){
        return (l+r)/2;
    }
}node[M*4];
struct {
    LL head;
}H[M];
struct {
    LL v,next;
}E[M];
void add(LL u,LL v){
    E[tp].v = v;
    E[tp].next = H[u]. head;
    H[u].head = tp++;
}

void dfs_1(LL u,LL fa){

    son[u] = 0;siz[u] = 1;father[u] = fa; dep[u] = dep[fa] + 1;
    for(LL i=H[u].head;i!=-1;i=E[i].next){
        LL v = E[i].v;
        if(v == fa)continue;
        dfs_1(v,u);
        siz[u] += siz[v];
        if(siz[v] > siz[son[u]])son[u] = v ;
    }
}
void dfs_2(LL u,LL fa){
    ti[u] = idx++;
    top[u] = fa;
    if(son[u])dfs_2(son[u],fa);
    for(LL i=H[u].head;i!=-1;i = E[i].next){
        LL v = E[i].v;
        if(v == father[u]||v == son[u]) continue;
        dfs_2(v,v);
    }

}
/* 线段树*/
void build_tree(LL id,LL l,LL r){
    node[id].l = l;
    node[id].r = r;
    node[id].sum = 0;
    if(l == r) return;
    LL mid = node[id].mid();
    build_tree(lson,l,mid);
    build_tree(rson,mid+1,r);
}
void push_up(LL id){
    node[id].sum = node[lson].sum   +   node[rson].sum;
}
void update(LL id,LL k,LL w){
    if(node[id].l == k&&node[id].r == k){
        node[id].sum = w;
        return;
    }
    LL mid = node[id].mid();
    if(k <=mid)update(lson,k,w);
    else update(rson,k,w);
    push_up(id);
}
LL query(LL id,LL l,LL r){
    if(node[id].l == l && node[id].r == r)
        return node[id].sum;
    LL mid = node[id].mid();
    if(r <=mid )return query(lson,l,r);
    else if(l > mid)return query(rson,l,r);
    else {
        return query(lson,l,mid) + query(rson,mid+1,r);
    }
}
LL e[M][4];
LL findmax(LL u,LL v){
    LL f1 = top[u];
    LL f2 = top[v];
    int sum = 0;
    while(f1 != f2){
        if(dep[f1] < dep[f2]){
            swap(f1,f2);swap(u,v);
        }
        sum += query(1,ti[f1],ti[u]);
         u = father[f1];f1 = top[u];
    }
    if(u == v) return sum;
    if(dep[u] > dep[v] ) swap(u,v);
    sum += query(1,ti[son[u]],ti[v]);
    return sum;
}
void init(){
    memset(E,-1,sizeof(E));
    memset(H,-1,sizeof(H));
    tp = 0;
    idx = 0;
    memset(son,0,sizeof(son));
}
int main(){
   //freopen("input.txt","r",stdin);
    LL n,m,u,v,w;
    while(~scanf("%d%d",&n,&m)){
            init();
        for(LL i=0;i<n-1;i++){
            scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
            add(e[i][0],e[i][1]);
            add(e[i][1],e[i][0]);
        }
        dfs_1(1,1);
        dfs_2(1,1);
        build_tree(1,1,idx-1);
        for(LL i=0;i<n-1;i++){
            if(dep[e[i][0]] > dep[e[i][1]])
                swap(e[i][0],e[i][1]);
                update(1,ti[e[i][1]],e[i][2]);
        }
        while(m --){
            scanf("%d%d%d",&w,&u,&v);
            if(w)printf("%d\n",findmax(u,v));
            else update(1,ti[e[u-1][1]],v);
        }
    }
}
时间: 2024-08-16 10:51:45

foj 2082 树链剖分 第2天的相关文章

FZU 2082 树链剖分

点击打开链接 题意:中文 思路:最基础的树链剖分,区间求和以及单点更新,结果要用long long 就没什么了 #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; ty

FZU 2082 过路费 (树链剖分)边权

Problem 2082 过路费 Accept: 322    Submit: 1101 Time Limit: 1000 mSec    Memory Limit : 32768 KB Problem Description 有n座城市,由n-1条路相连通,使得任意两座城市之间可达.每条路有过路费,要交过路费才能通过.每条路的过路费经常会更新,现问你,当前情况下,从城市a到城市b最少要花多少过路费. Input 有多组样例,每组样例第一行输入两个正整数n,m(2 <= n<=50000,1&

FZU 2082 过路费 (树链剖分)

树链剖分裸题...不多说.. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <stdio.h> using namespace

树链剖分 FZU 2082

#include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int maxn = 50005; int val[maxn]; struct node { int l,r; long long sum; } xds[maxn<<2]; void build(int ID,int l,int r) { xds[ID].l=l; xds[ID].r=r; if(

FZU2082 树链剖分(单点更新区间求值)

http://acm.fzu.edu.cn/problem.php?pid=2082  Problem Description 有n座城市,由n-1条路相连通,使得任意两座城市之间可达.每条路有过路费,要交过路费才能通过.每条路的过路费经常会更新,现问你,当前情况下,从城市a到城市b最少要花多少过路费.  Input 有多组样例,每组样例第一行输入两个正整数n,m(2 <= n<=50000,1<=m <= 50000),接下来n-1行,每行3个正整数a b c,(1 <=

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

bzoj3694: 最短路(树链剖分/并查集)

bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最短路径树上的边x->y,设t为最短路径树上lca(x,y),则t到y上的路径上的点i到根的距离都可以用h[x]+dis[x][y]+h[y]-h[i](h[]为深度)来更新,因为h[i]一定,只要让h[x]+dis[x][y]+h[y]最小就行,这里用树剖直接修改整条链上的数,就可以过了. 并查集的

洛谷 P3384 【模板】树链剖分

题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数N.M.R.P,分别表示树的结点个数.操作个数