OrzFAng 233–树 解题报告

Posted zhouyis

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OrzFAng 233–树 解题报告相关的知识,希望对你有一定的参考价值。

题目描述

方方方种下了三棵树,两年后,第二棵树长出了n个节点,其中1号节点是根节点。

给定一个n个点的树

支持两种操作

方方方进行m次操作,每个操作为:

(1)给出两个数i,x,将第i个节点的子树中,与i距离为斐波那契数的节点权值+x(包括i本身)。

(2)给出一个数i,求出第i个节点的子树中,与i距离为斐波那契数的节点的权值和(包括i本身)。

 

题解

斐波那契数列f_i=f_{i-1}+f_{i-2}

首先这个会被操作的只有大概25层的节点。

这样深度相同的区间在bfs序上是连续的区间,那么只要求出这样的左右端点是哪些,后面的就可以建个线段树|树状数组维护

原来我觉得这样的区间很难求。其实只要类似倍增的做法Fa_{i,j}表示i的f_i次祖先。就可以直接求了。

bfs序上的区间修改/查询 还可以用bit

这类的玩意http://www.cnblogs.com/zzqsblog/p/5692627.html

#include<map>
#include<stack>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<complex>
#include<iostream>
#include<assert.h>
#include<algorithm>
using namespace std;
#define inf 1001001001
#define infll 1001001001001001001LL
#define ll long long
#define dbg(vari) cerr<<#vari<<" = "<<(vari)<<endl
#define gmax(a,b) (a)=max((a),(b))
#define gmin(a,b) (a)=min((a),(b))
#define Ri register int
#define gc getchar()
#define il inline
il int read(){
    bool f=true;Ri x=0;char ch;while(!isdigit(ch=gc))if(ch==\'-\')f=false;while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-\'0\';ch=gc;}return f?x:-x;
}
#define gi read()
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
struct edge{
    int to,next;
}e[501234];
int last[123456],dep[123456],val[123456],f[123456][34],cnt,n,m;
ll sum;
il void link(int a,int b){
    e[++cnt]=(edge){b,last[a]};last[a]=cnt;
    e[++cnt]=(edge){a,last[b]};last[b]=cnt;
}
int lf[123456][34],rf[123456][34],bfn[123456],_bfn;
// i的fib_i层的左&右 
void dfs(int x,int fa=0){
    dep[x]=dep[fa]+1;
    f[x][1]=f[x][2]=fa;
    for(int i=3;i<=30;i++)f[x][i]=f[f[x][i-2]][i-1];
    for(int i=last[x];i;i=e[i].next){
        if(e[i].to!=fa){
            dfs(e[i].to,x); 
        }
    } 
}
bool vis[123456];
void bfs(int s){
    memset(vis,0,sizeof(vis));
    queue<int>q;
    q.push(s);vis[s]=true;bfn[1]=++_bfn;
    while(!q.empty()){
        int c=q.front();q.pop();
        for(int i=last[c];i;i=e[i].next){
            if(!vis[e[i].to]){
                q.push(e[i].to);
                vis[e[i].to]=true;
                bfn[e[i].to]=++_bfn;
            }
        }
    }     
}
void yuchuli(){
    dfs(1); 
    bfs(1);
    memset(lf,127,sizeof(lf));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=30;j++){
            int anc=f[i][j];
            if(!anc)break;
            gmin(lf[anc][j],bfn[i]);
            gmax(rf[anc][j],bfn[i]); 
        }
    } 
    for(int i=1;i<=n;i++)
        lf[i][1]=rf[i][1]=bfn[i];
}
namespace bit{
    ll a1[234567],a2[234567];
    ll qzh(int r){
        ll s1=0,s2=0;
        for(int i=r;i>=1;i-=i&-i) s1+=a1[i], s2+=a2[i];
        return (r+1)*s1-s2;
    }
    ll sum(int l,int r){
        return qzh(r)-qzh(l-1);
    }
    void edt(ll a,ll s1){
        ll s2=a*s1;
        for(;a<=n;a+=a&-a) a1[a]+=s1, a2[a]+=s2;
    }
    void edt(int l,int r,ll a) {edt(l,a); edt(r+1,-a);}
}
void _chg(int x,int y){
    for(int i=1;i<=30;i++){
        if(!rf[x][i])break;
        bit::edt(lf[x][i],rf[x][i],y);
    }
}
ll _qry(int x){
    sum=0;
    for(int i=1;i<=30;i++){
        if(!rf[x][i])break;
        sum=sum+bit::sum(lf[x][i],rf[x][i]);
    }
    return sum;
} 
int main(){
    //FO(tree2);
    n=gi;m=gi;
    for(int i=1;i<n;i++){
        int a,b;
        a=gi;b=gi;
        link(a,b);
    }
    yuchuli();
    while(m--){
        int op,x,y;
        op=gi;
        if(op==2){
            x=gi;
            printf("%I64d\\n",_qry(x)); 
        }
        if(op==1){
            x=gi;y=gi;
            _chg(x,y);
            //puts("");
        }
    }
}

以上是关于OrzFAng 233–树 解题报告的主要内容,如果未能解决你的问题,请参考以下文章

poj2528线段树解题报告,离散化+线段树

2020.3.14 解题报告

HDU 3791二叉搜索树解题(解题报告)

POJ2728最优比率生成树解题报告

655. Print Binary Tree 解题报告(树)

codeforces 160A-C语言解题报告