LIGHTOJ 1348 树链剖分

点击打开链接

题意:给一个树和树上点的权值,两个操作,一个是将点的权值修改,一个是询问u到v的点权和

思路:模版题,kuangbin开的这套题为什么这么模版的写的人这么少,可能大神们不屑于写这种题吧(弱哭)

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=30010;
int fa[maxn],siz[maxn],son[maxn],w[maxn],p[maxn],dep[maxn],fp[maxn],Rank[maxn],A[maxn];
//fa为父节点,siz为子节点中siz最大的,dep为深度,son为重儿子,w表示在线段树中的位置
int num[maxn<<2];
int tree_id,n;
vector<int>G[maxn];
void dfs1(int u,int ff,int deep){
    son[u]=0;fa[u]=ff;siz[u]=1;dep[u]=deep;
    for(unsigned int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v==ff) continue;
        dfs1(v,u,deep+1);
        siz[u]+=siz[v];
        if(siz[v]>siz[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int ff){
    w[u]=++tree_id;p[u]=ff;Rank[w[u]]=u;
    if(son[u]) dfs2(son[u],ff);
    else return ;
    for(unsigned int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
    }
}
void buildtree(int le,int ri,int node){
    if(le==ri){
        num[node]=A[Rank[le]];
        return ;
    }
    int t=(le+ri)>>1;
    buildtree(le,t,node<<1);
    buildtree(t+1,ri,node<<1|1);
    num[node]=num[node<<1]+num[node<<1|1];
}
void update(int pos,int val,int le,int ri,int node){
    if(le==ri){
        num[node]=val;
        return ;
    }
    int t=(le+ri)>>1;
    if(pos<=t) update(pos,val,le,t,node<<1);
    else update(pos,val,t+1,ri,node<<1|1);
    num[node]=num[node<<1]+num[node<<1|1];
}
int query(int l,int r,int le,int ri,int node){
    if(l<=le&&ri<=r) return num[node];
    int t=(le+ri)>>1,ans=0;
    if(l<=t) ans+=query(l,r,le,t,node<<1);
    if(r>t) ans+=query(l,r,t+1,ri,node<<1|1);
    return ans;
}
int getans(int u,int v){
    int f1=p[u],f2=p[v],tmp=0;
    while(f1!=f2){
        if(dep[f1]<dep[f2]){
            swap(f1,f2);
            swap(u,v);
        }
        tmp+=query(w[f1],w[u],1,n,1);
        u=fa[f1];f1=p[u];
    }
    if(dep[u]>dep[v]) swap(u,v);
    tmp+=query(w[u],w[v],1,n,1);
    return tmp;
}
int main(){
    int m,q,u,v,T,cas=1,op;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&A[i]);
        for(int i=0;i<maxn;i++) G[i].clear();
        memset(son,0,sizeof(son));tree_id=0;
        for(int i=0;i<n-1;i++){
            scanf("%d%d",&u,&v);
            u++;v++;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs1(1,1,0);
        dfs2(1,1);
        buildtree(1,n,1);
        scanf("%d",&q);
        printf("Case %d:\n",cas++);
        while(q--){
            scanf("%d",&op);
            if(op==0){
                scanf("%d%d",&u,&v);
                u++;v++;
                printf("%d\n",getans(u,v));
            }else{
                scanf("%d%d",&u,&v);
                u++;
                update(w[u],v,1,n,1);
            }
        }
    }
    return 0;
}
时间: 2024-10-08 13:05:52

LIGHTOJ 1348 树链剖分的相关文章

light oj 1348 树链剖分(单点更新区间求值)

http://lightoj.com/volume_showproblem.php?problem=1348 Finally the Great Magical Lamp was in Aladdin's hand. Now he wanted to return home. But he didn't want to take any help from the Genie because he thought that it might be another adventure for hi

LightOJ 1348 Aladdin and the Return Journey (树链剖分)

树链剖分模板题. 最近一直有比赛..好长时间没写了.明显生疏了..找个模板题熟悉一下. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include &l

Light 1348 - Aladdin and the Return Journey(树链剖分)

Light 1348 - Aladdin and the Return Journey 题目链接 树链剖分基础题,注意一个坑点,就是下标按0开始的话按我的写法是会错的,因为son初值赋成0了,要么改一下son初值,要么把下标都+1 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N =

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,分别表示树的结点个数.操作个数

bzoj1036 树的统计(树链剖分+线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 15120  Solved: 6141[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

SPOJ QTREE Query on a tree ——树链剖分 线段树

[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20005 int T,n,fr[maxn],h[maxn],to[maxn],ne[maxn]