这里枚举了树的DFS序来解决树上问题的多个板子,自己最好多看看。

↓改↓ ↓求↓
————————>>>这个就算了
简单, BIT
重点!
简单, 线段树
重重点!!!
简单, BIT+差分
重重点!!!
重重点!!!
重重点!!!

给定一颗树, 和每个节点的权值

1.对某个节点X权值加上一个数W, 查询某个子树X里所有点权的和

改点求树

这个不说什么,果断就BIT维护区间和,即改点求段。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000;
inline int Read(){
    int x=0,f=0;char ch;
    while(!isdigit(ch=getchar()))if(ch=='-') f=1;
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return f?-x:x;
}
vector<int> tree[MAXN];
int seq[MAXN],st[MAXN],ed[MAXN];
int n,x,y,cnt,q,m;

inline int lowbit(int x){return x&-x;}
inline void Add(int x,int k){while(x<=n) seq[x]+=k,x+=lowbit(x);}
inline int Sum(int x){int ans=0;while(x>0) ans+=seq[x],x-=lowbit(x);return ans;}

void DFS(int fa,int rt){
    st[rt]=++cnt;
    for(register int i=0;i<tree[rt].size();++i) if(tree[rt][i]!=fa) DFS(rt,tree[rt][i]);
    ed[rt]=cnt;
}

int main(){
    n=Read(),m=Read();//root------1
    for(register int i=1;i<n;++i) x=Read(),y=Read(),tree[x].push_back(y),tree[y].push_back(x);
    DFS(0,1);
    for(register int i=1;i<=n;++i) y=Read(),Add(st[i],y);
    for(register int i=1;i<=m;++i){
        q=Read();x=Read();
        if(q==1) y=Read(),Add(st[x],y);
        else printf("%d\n",Sum(ed[x])-Sum(st[x]-1));
    }
    return 0;
}

2.对节点X到Y的最短路上所有点权都加一个数W, 查询某个点的权值

改链求点

思路:操作等价于是:

1.对X到根节点路径上所有点权加W
2.对Y到根节点路径上所有点权加W
3.对LCA(x, y)到根节点路径上所有点权值减W
4.对LCA(x,y)的父节点 parent(LCA(x,y))parent(LCA(x, y))parent(LCA(x,y))到根节点路径上所有权值减W

这里的操作我 用一个树状数组seq[i]seq[i]seq[i]表示在DFS序里的节点i到根节点的整体被操作的值,这样操作1就是Add(st[x],w)Add(st[x],w)Add(st[x],w) 2,3,4同理。查询自己看代码想一想,就是子树中总共的操作值。(感谢@hankeke帮助juruo理解)

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000;
const int Log=19;
inline int Read(){
    int x=0,f=0;char ch;
    while(!isdigit(ch=getchar()))if(ch=='-') f=1;
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return f?-x:x;
}
vector<int> tree[MAXN];
int f[MAXN][Log+2];
int seq[MAXN],st[MAXN],ed[MAXN],A[MAXN],depth[MAXN],s[MAXN];
int n,x,y,cnt,q,m,w;

inline int lowbit(int x){return x&-x;}
inline void Add(int x,int k){if(!x) return; while(x<=n) seq[x]+=k,x+=lowbit(x);}
inline int Sum(int x){int ans=0;while(x>0) ans+=seq[x],x-=lowbit(x);return ans;}

void Power(int k,int tot){
    while(k<=n+1){
        int kk=k;k<<=1;
        for(register int i=kk;i<=k-1;++i) s[i]=tot;
        ++tot;
    }
}

void DFS(int fa,int rt){
    st[rt]=++cnt;f[rt][0]=fa;depth[rt]=depth[fa]+1;
    for(register int j=1;(1<<j)<=depth[rt];++j) f[rt][j]=f[f[rt][j-1]][j-1];
    for(register int i=0;i<tree[rt].size();++i) if(tree[rt][i]!=fa) DFS(rt,tree[rt][i]);
    ed[rt]=cnt;
}

inline int LCA(int x,int y){
    if(depth[x]<depth[y]) x^=y^=x^=y;
    for(register int k=/*s[depth[x]-depth[y]]*/19;k>=0;--k) if(depth[f[x][k]]>=depth[y]) x=f[x][k];
    if(x==y) return x;
    for(register int k=/*s[depth[x]-1]*/19;k>=0;--k) if(f[x][k]!=f[y][k]) x=f[x][k],y=f[y][k];
    return f[x][0];
}

int main(){//freopen("tmp.txt","r",stdin);
    n=Read(),m=Read();//root------1
    for(register int i=1;i<n;++i) x=Read(),y=Read(),tree[x].push_back(y),tree[y].push_back(x);
    DFS(0,1);//Power(1,0);
    for(register int i=1;i<=n;++i) A[i]=Read();
    for(register int i=1;i<=m;++i){
        q=Read();
        if(q==1){
            x=Read(),y=Read(),w=Read();
            int lca=LCA(x,y);
            Add(st[x],w);Add(st[y],w);Add(st[lca],-w);Add(st[f[lca][0]],-w);
        }
        else x=Read(),printf("%d\n",A[x]+Sum(ed[x])-Sum(st[x]-1));
    }
    return 0;
}

3.对节点X到Y的最短路上所有点权都加一个数W, 查询某个点子树的权值之和

改链求树

思路极乱

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000;
const int Log=19;
inline int Read(){
    int x=0,f=0;char ch;
    while(!isdigit(ch=getchar()))if(ch=='-') f=1;
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return f?-x:x;
}
vector<int> tree[MAXN];
int f[MAXN][Log+2];
int seq1[MAXN],seq2[MAXN],depth[MAXN],sum[MAXN];
int st[MAXN],ed[MAXN];
int n,x,y,cnt,q,m,w;

inline int lowbit(int x){return x&-x;}
inline void Add1(int x,int k){if(!x) return; while(x<=n) seq1[x]+=k,x+=lowbit(x);}
inline int Sum1(int x){int ans=0;while(x>0) ans+=seq1[x],x-=lowbit(x);return ans;}
inline void Add2(int x,int k){if(!x) return; while(x<=n) seq2[x]+=k,x+=lowbit(x);}
inline int Sum2(int x){int ans=0;while(x>0) ans+=seq2[x],x-=lowbit(x);return ans;}
/*
void Power(int k,int tot){
    while(k<=n+1){
        int kk=k;k<<=1;
        for(register int i=kk;i<=k-1;++i) s[i]=tot;
        ++tot;
    }
}
*/
void DFS(int fa,int rt){
    st[rt]=++cnt;f[rt][0]=fa;depth[rt]=depth[fa]+1;
    for(register int j=1;(1<<j)<=depth[rt];++j) f[rt][j]=f[f[rt][j-1]][j-1];
    for(register int i=0;i<tree[rt].size();++i) if(tree[rt][i]!=fa) DFS(rt,tree[rt][i]);
    ed[rt]=cnt;
}

inline int LCA(int x,int y){
    if(depth[x]<depth[y]) x^=y^=x^=y;
    for(register int k=/*s[depth[x]-depth[y]]*/19;k>=0;--k) if(depth[f[x][k]]>=depth[y]) x=f[x][k];
    if(x==y) return x;
    for(register int k=/*s[depth[x]-1]*/19;k>=0;--k) if(f[x][k]!=f[y][k]) x=f[x][k],y=f[y][k];
    return f[x][0];
}

int main(){//freopen("tmp.txt","r",stdin);
    n=Read(),m=Read();//root------1
    for(register int i=1;i<n;++i) x=Read(),y=Read(),tree[x].push_back(y),tree[y].push_back(x);
    DFS(0,1);//Power(1,0);
    for(register int i=1;i<=n;++i) sum[st[i]]=Read();
    for(register int i=1;i<=n;++i) sum[i]+=sum[i-1];
    for(register int i=1;i<=m;++i){
        q=Read();
        if(q==1){
            x=Read(),y=Read(),w=Read();
            int lca=LCA(x,y);
            Add1(st[x],w);Add1(st[y],w);Add1(st[lca],-w);Add1(st[f[lca][0]],-w);
            Add2(st[x],w*(depth[x]+1));Add2(st[y],w*(depth[y]+1));Add2(st[lca],-w*(depth[lca]+1));Add2(st[f[lca][0]],-w*(depth[f[lca][0]]+1));
        }
        else x=Read(),printf("%d\n",sum[ed[x]]-sum[st[x]-1]+Sum2(ed[x])-Sum2(st[x]-1)-(Sum1(ed[x])-Sum1(st[x]-1))*depth[x]);
    }
    return 0;
}

4.对某个点X权值加上一个数W, 查询X到Y路径上所有点权之和

改点求链

用一个树状数组seq[i]seq[i]seq[i]表示在DFS序里的节点i到根节点的链权值和被加一个w,x到y的路径亦可拆成4条,改一个点以后就用差分思想把其子树点区间加w(树状数组区间修改seq,求点),查询时对x和y到根的链预处理好的权值和加上总操作值。可对比T2。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000;
const int Log=19;
inline int Read(){
    int x=0,f=0;char ch;
    while(!isdigit(ch=getchar()))if(ch=='-') f=1;
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return f?-x:x;
}
vector<int> tree[MAXN];
int f[MAXN][Log+2];
int len[MAXN],st[MAXN],ed[MAXN],A[MAXN],depth[MAXN],sum[MAXN];
int n,x,y,cnt,q,m,w;

inline int lowbit(int x){return x&-x;}
inline void Add(int x,int k){if(!x) return; while(x<=n) len[x]+=k,x+=lowbit(x);}
inline int Sum(int x){int ans=0;while(x>0) ans+=len[x],x-=lowbit(x);return ans;}
/*
void Power(int k,int tot){
    while(k<=n+1){
        int kk=k;k<<=1;
        for(register int i=kk;i<=k-1;++i) s[i]=tot;
        ++tot;
    }
}
*/
void DFS(int fa,int rt){
    st[rt]=++cnt;f[rt][0]=fa;depth[rt]=depth[fa]+1;sum[rt]=sum[fa]+A[rt];
    for(register int j=1;(1<<j)<=depth[rt];++j) f[rt][j]=f[f[rt][j-1]][j-1];
    for(register int i=0;i<tree[rt].size();++i) if(tree[rt][i]!=fa) DFS(rt,tree[rt][i]);
    ed[rt]=cnt;
}

inline int LCA(int x,int y){
    if(depth[x]<depth[y]) x^=y^=x^=y;
    for(register int k=/*s[depth[x]-depth[y]]*/19;k>=0;--k) if(depth[f[x][k]]>=depth[y]) x=f[x][k];
    if(x==y) return x;
    for(register int k=/*s[depth[x]-1]*/19;k>=0;--k) if(f[x][k]!=f[y][k]) x=f[x][k],y=f[y][k];
    return f[x][0];
}

int main(){//freopen("tmp.txt","r",stdin);
    n=Read(),m=Read();//root------1
    for(register int i=1;i<n;++i) x=Read(),y=Read(),tree[x].push_back(y),tree[y].push_back(x);
    for(register int i=1;i<=n;++i) A[i]=Read();
    DFS(0,1);//Power(1,0);
    for(register int i=1;i<=m;++i){
        q=Read();
        if(q==1) x=Read(),w=Read(),Add(st[x],w),Add(ed[x]+1,-w);
        else{
            x=Read(),y=Read();
            int lca=LCA(x,y);printf("%d\n",sum[x]+sum[y]-sum[lca]-sum[f[lca][0]]+Sum(st[x])+Sum(st[y])-Sum(st[lca])-Sum(st[f[lca][0]]));
        }
    }
    return 0;
}

5.对子树X里所有节点加上一个值W, 查询某个点的值

改树求点

BIT+差分,水过。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000;
inline int Read(){
    int x=0,f=0;char ch;
    while(!isdigit(ch=getchar()))if(ch=='-') f=1;
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return f?-x:x;
}
vector<int> tree[MAXN];
int seq[MAXN],st[MAXN],ed[MAXN],A[MAXN];
int n,x,y,cnt,q,m;

inline int lowbit(int x){return x&-x;}
inline void Add(int x,int k){while(x<=n) seq[x]+=k,x+=lowbit(x);}
inline int Sum(int x){int ans=0;while(x>0) ans+=seq[x],x-=lowbit(x);return ans;}

void DFS(int fa,int rt){
    st[rt]=++cnt;
    for(register int i=0;i<tree[rt].size();++i) if(tree[rt][i]!=fa) DFS(rt,tree[rt][i]);
    ed[rt]=cnt;
}

int main(){
    n=Read(),m=Read();//root------1
    for(register int i=1;i<n;++i) x=Read(),y=Read(),tree[x].push_back(y),tree[y].push_back(x);
    DFS(0,1);
    for(register int i=1;i<=n;++i) A[i]=Read();
    for(register int i=1;i<=m;++i){
        q=Read();x=Read();
        if(q==1) y=Read(),Add(st[x],y),Add(ed[x]+1,-y);
        else printf("%d\n",A[x]+Sum(st[x]));
    }
    return 0;
}

6.对子树X里所有节点加上一个值W, 查询某个子树的值

改树求树

线段树,区间修改区间查询水过。其实BIT也是可以的,看这里树状数组区间修改区间查询1或者这里树状数组区间修改区间查询2

#include<bits/stdc++.h>
#define l i<<1
#define r i<<1|1
#define mid ((L+R)>>1)
using namespace std;
const int MAXN=100000;
inline int Read(){
    int x=0,f=0;char ch;
    while(!isdigit(ch=getchar()))if(ch=='-') f=1;
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return f?-x:x;
}
vector<int> tree[MAXN];
int st[MAXN],ed[MAXN],A[MAXN];
int sum[MAXN<<2],add[MAXN<<2];
int n,x,y,cnt,q,m,ql,qr,w;

void build(int i,int L,int R){
    if(L==R)sum[i]=A[L];
    else build(l,L,mid),build(r,mid+1,R),sum[i]=sum[l]+sum[r];
}

inline void pushdown(int i,int L,int R){
    if(add[i]) sum[l]+=(mid-L+1)*add[i],sum[r]+=(R-mid)*add[i],add[l]+=add[i],add[r]+=add[i],add[i]=0;
}

inline void Add(int i,int L,int R){
    if(ql<=L&&qr>=R){sum[i]+=w*(R-L+1),add[i]+=w;return;}
    pushdown(i,L,R);
    if(ql<=mid) Add(l,L,mid);if(qr>mid) Add(r,mid+1,R);
    sum[i]=sum[l]+sum[r];
}

inline int Query(int i,int L,int R){
    if(ql<=L&&qr>=R) return sum[i];
    pushdown(i,L,R);int ans=0;
    if(ql<=mid) ans+=Query(l,L,mid);if(qr>mid) ans+=Query(r,mid+1,R);
    return ans;
}

void DFS(int fa,int rt){
    st[rt]=++cnt;
    for(register int i=0;i<tree[rt].size();++i) if(tree[rt][i]!=fa) DFS(rt,tree[rt][i]);
    ed[rt]=cnt;
}

int main(){
    n=Read(),m=Read();//root------1
    for(register int i=1;i<n;++i) x=Read(),y=Read(),tree[x].push_back(y),tree[y].push_back(x);
    DFS(0,1);
    for(register int i=1;i<=n;++i) A[st[i]]=Read();
    build(1,1,n);
    for(register int i=1;i<=m;++i){
        q=Read(),x=Read();ql=st[x],qr=ed[x];
        if(q==1) w=Read(),Add(1,1,n);
        else printf("%d\n",Query(1,1,n));
    }
    return 0;
}

7.对于子树X内的所有点都加上一个值W,查询X到Y之间的路径上所有点权和。

改树求链

写不动了。。

8.补充

改点求点

改点求链?

改链求链?

瞎写的树dfs序的更多相关文章

  1. S - Query on a tree HDU - 3804 线段树+dfs序

    S - Query on a tree HDU - 3804   离散化+权值线段树 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度. 这个题目和之前写的那个给你一棵 ...

  2. HDU 5692 线段树+dfs序

    Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  3. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  4. 51 nod 1681 公共祖先 (主席树+dfs序)

    1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题   有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...

  5. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  6. 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序

    题目大意 ​ Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜 ...

  7. 【BZOJ】3991: [SDOI2015]寻宝游戏 虚树+DFS序+set

    [题意]给定n个点的带边权树,对于树上存在的若干特殊点,要求任选一个点开始将所有特殊点走遍后返回.现在初始没有特殊点,m次操作每次增加或减少一个特殊点,求每次操作后的总代价.n,m<=10^5. ...

  8. 【bzoj4817】树点涂色 LCT+线段树+dfs序

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  9. 【BZOJ1803】Spoj1487 Query on a tree III 主席树+DFS序

    [BZOJ1803]Spoj1487 Query on a tree III Description You are given a node-labeled rooted tree with n n ...

随机推荐

  1. mini2440裸机试炼之——Uart与pc端实现文件、字符传输

    1.  波特率(Baud rate)即调制速率,1波特即指每秒传输1个符号. 2.  非FIFO模式,即数据传输不利用FIFO缓存,一个字节一个字节地传输. 3.  位能够用来推断发送缓存器中是否为空 ...

  2. Android TelephonyManager类的使用

    TelephonyManager类主要提供了一系列获取手机与通讯相关的状态和信息的get方法,包含手机用户的信息.手机SIM的状态.电信网络的状态等. TelephonyManager类的对象的获取: ...

  3. dnSpy进行反编译修改并编译运行EXE或DLL

    dnSpy对目标程序(EXE或DLL)进行反编译修改并编译运行 本文为原创文章.源代码为原创代码,如转载/复制,请在网页/代码处明显位置标明原文名称.作者及网址,谢谢! 本文使用的工具下载地址为: h ...

  4. Koa2+MySQL+VUE+ElementIUI搭建简单的后台管理小系统

    如题,前端入坑许久,还是写个小东西出来吧 想要搭建自己的一个后台管理,实现简单的增删改查,看起来很简单 其实是真的简单,没有想的那么难,我也就写了一个月吧, 当然是假的,其实也就每天一两个小时,花了大 ...

  5. python 基础 1.5 python数据类型(四)--字典常用方法示例

    一. 字典 #字典 dict1 = {'name':'lzc','age':'20','sex':'man'} print dict1 print type(dict1) >>> { ...

  6. EasyPlayerPro windows播放器本地音频播放音量控制实现

    背景描述 作为一个播放器, 除了能播放视频和声音外,音量控制是绝对不能缺少的功能; 本文在音视频播放的基础上,增加对音量的控制: 实现流程 调用mixerGetDevCaps获取音频输出设备列表; 打 ...

  7. struct对齐

    1 基本数据类型的自然对齐 就是说,基本数据类型的变量不能随便放在内存的任意位置,它们的起始地址必须被它们的大小整除. double是8个字节,float,int,enum是4字节,bool.char ...

  8. SSL:Ubuntu证书配置

    CA证书的配置 Ubuntu上CA证书的配置可以通过工具ca-certificates来方便的进行.该工具默认是随Ubuntu安装的,如果没有可以通过下面的命令来安装: sudo apt-get in ...

  9. Eclipse使用方法和技巧二十六:浅谈快捷键

            网络上到处都是eclipse有哪些经常使用的快捷键,当中还有非常多讲得着实不错.这里就不再狗尾续貂而是谈谈别的这段时间的一些思考.近期增加了开发团队.代码量突突的上去了.同一时候也发现 ...

  10. Arcgis SOE学习

    http://blog.csdn.net/lovecarpenter/article/details/53178233 http://blog.csdn.net/lovecarpenter/artic ...