DFS序--树状数组

这里先说下有关大法师(DFS序)的内容....

子树修改----求子树和

  • 虽然就是一个简(\(fang\)) 单 ( \(pi\) ) 的 区间修改,加上区间查询

  • 有人就会“密西”道:这不线段树嘛,有手就行。

  • 也许还会有人会曰:线段树他不香吗?


But...

  • 我用的树状数组 (/滑稽/)

因此 我来交代一下我的做法

树状数组学好了吗,看看这吧,guy!


请看Code

  • 方便读者进行修改,加以理解的代码

```cpp
/*
 DFSN: 子树修改,子树查询。 
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
const int manx = 1e5 + 10;
const int mod = 1234567890;
const int minx = 1e7 + 10;
struct node{
    int u;
    int v;
    int nxt;
    int w;
}e[manx<<1];
int cur,sum[manx],summ[manx],head[manx],deep[manx],js,l[manx],r[manx],cnt,n,m,dfn[manx];
int add(int u,int v){
    e[++cnt].u = u;
    e[cnt].nxt = head[u];
    e[cnt].v = v;
    //e[cnt].w = w;
    head[u] = cnt;
}
inline void init(){
    cnt=js=0;
    clr(head,-1);clr(sum,0);
    cur=n<<1;
}
void dfs(int u, int pre){
     //cout<<1<<endl;
    l[u] = ++js;
    dfn[js] = u;
    for(int i = head[u];~i;i = e[i].nxt){
        int v = e[i].v;
        if( v == pre ) continue;
        dfs(v,u);
    }
    r[u] = ++js;
    dfn[js] = u;    
}
struct Binary_tree{
long long tr[manx];
void add(int i,long long x)
{
	//cout<<i<<" "<<x<<endl;
    while(i<=n*2)
    {
        tr[i]+=x;
        i+=i&-i;
    }
}
long long qsum(int i)
{
    long long ret=0;
    while(i>0)
    {
        ret+=tr[i];
        i-=i&-i;
    }
    return ret;
}
}A,B;
int main(){
    cin>>n>>m;
    init();
    for(int i = 1; i <= n - 1;i ++){
    int x;int y;
    cin>>x>>y;
    add(x,y);
    add(y,x);
    }	
    dfs(1,1); 
    for(int i = 1;i <= m; i++){
        int x;int y;int z;
        cin>>x>>y;
        if(x == 1){
            cin>>z;
            A.add(l[y],z);
            A.add(r[y]+1,-z);
            B.add(l[y],z*(l[y]-1));
            B.add(r[y]+1,-z*r[y]);
//            cout<<A.tr [l[y]]<<" "<<A.tr [r[y]+1]<<endl;
//            for(int j = 1;j <= n *2;j ++)
//            cout<<A.tr[j]<<" ";
//            cout<<endl;
//            for(int j = 1;j <= n *2;j ++)
//	        cout<<B.tr[j]<<" ";
//            cout<<endl;
        }
        else
        {
//            for(int j = 1;j <= n*2;j++)
//            cout<<j<<" "<<A.qsum(j)<<" "<<endl;
//            for(int j = 1;j <= n*2;j++)
//            cout<<j<<" "<<B.qsum(j)<<" "<<endl;
//            for(int j = 1; j <= n;j++)
//            cout<<j<<" "<<l[j]<<" "<<r[j]<<endl; 
            cout<<(A.qsum(r[y])*r[y]-(l[y]-1)*A.qsum(l[y]-1))-B.qsum(r[y])+B.qsum(l[y]-1);   
        }
    }
}

  • 简洁的Code


/*
 DFSN: 子树修改,子树查询。 
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<string.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;

const int manx = 1e5 + 10;
const int mod = 1234567890;
const int minx = 1e7 + 10;

struct node{
    int u;
    int v;
    int nxt;
    int w;
}e[manx<<1];
int cur,sum[manx],summ[manx],head[manx],deep[manx],js,l[manx],r[manx],cnt,n,m,dfn[manx];
int add(int u,int v){
    e[++cnt].u = u;
    e[cnt].nxt = head[u];
    e[cnt].v = v;
    //e[cnt].w = w;
    head[u] = cnt;
}

inline void init(){
    cnt=js=0;
    clr(head,-1);clr(sum,0);
    cur=n<<1;
}
void dfs(int u, int pre){
    l[u] = ++js;
    dfn[js] = u;
    for(int i = head[u];~i;i = e[i].nxt){
        int v = e[i].v;
        if( v == pre ) continue;
        dfs(v,u);
    }
    r[u] = ++js;
    dfn[js] = u;    
}

struct Binary_tree{
long long tr[manx];
void add(int i,long long x)
{
    while(i<=n*2)
    {
        tr[i]+=x;
        i+=i&-i;
    }
}
long long qsum(int i)
{
    long long ret=0;
    while(i>0)
    {
        ret+=tr[i];
        i-=i&-i;
    }
    return ret;
}
}A,B;
int main(){
    cin>>n>>m;
    init();
    for(int i = 1; i <= n - 1;i ++){
    int x;int y;
    cin>>x>>y;
    add(x,y);
    add(y,x);
    }	
    dfs(1,1); 
    for(int i = 1;i <= m; i++){
        int x;int y;int z;
        cin>>x>>y;
        if(x == 1){
            cin>>z;
            A.add(l[y],z);
            A.add(r[y]+1,-z);
            B.add(l[y],z*(l[y]-1));
            B.add(r[y]+1,-z*r[y]);
        }
        else
        {
            cout<<(A.qsum(r[y])*r[y]-(l[y]-1)*A.qsum(l[y]-1))-B.qsum(r[y])+B.qsum(l[y]-1);   
        }
    }
}


这里给个特别需要注意的地方

(因为我在这卡了一天)

void add(int i,long long x)
{
    while(i<=n*2)
    {
        tr[i]+=x;
        i+=i&-i;
    }
}

\(while\) 中的 \(i\) 的范围应该是 \(1...n\times2\) !!!

原因不想解释,可能因为我太菜了吧~~~

我想再填一句

其实树状数组局限性很大,比如这个题

颜色修改不容易实现

\(The \ End\)

posted @ 2020-11-02 22:13  zxsoul  阅读(216)  评论(0编辑  收藏  举报