树链剖分

解决:对于一株树(无向无环连通图),为每个结点分配对应的权重。要求能高效计算任意两个结点之间的路径的各类信息,其中包括路径长度(路径上所有结点的权重加总),路径中最大权重,最小权重等等。
思路:划分重链和轻边,通过两遍DFS把重链上节点的新编号都连接到一起。
以下代码实现:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+10;
struct Edge{
    int to,next;
}edge[MAXN*2];
int head[MAXN],tot;
int top[MAXN];  //v所在的重链的顶端节点
int fa[MAXN];   //父亲节点
int deep[MAXN]; //深度
int num[MAXN];  //v为根的子树节点数
int p[MAXN];    //v对应的位置
int fp[MAXN];   //和p数组相反
int son[MAXN];  //重儿子
int pos;
int mood;
int a[MAXN];
void init(){    //初始化
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 1;
    memset(son,-1,sizeof(son));
}
void addedge(int u,int v){  //加边
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs1(int u,int pre, int d){    //当前节点、父节点、层深度
    deep[u] = d;
    fa[u] = pre;
    num[u] = 1;
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        if(v != pre){
            dfs1(v,u,d+1);
            num[u] += num[v];
            if(son[u] == -1 || num[v] > num[son[u]])
                son[u]=v;
        }
    }

}
void getpos(int u ,int sp){
    top[u] = sp;
    p[u] = pos++;
    fp[p[u]] = u;
    if(son[u] == -1) return ;
    getpos(son[u],sp);
    for(int i = head[u] ; i != -1; i = edge[i].next){
        int v = edge[i].to;
        if(v != son[u] && v != fa[u])
            getpos(v,v);
    }
}
//线段树
struct Node{
    int l,r;
    int val,laz;
}segTree[MAXN*20];
void build(int i,int l,int r){
    segTree[i].l = l;
    segTree[i].r = r;
    segTree[i].laz = 0;
    if(l == r){
        segTree[i].val = a[fp[l]]%mood;;
        return ;
    }
    int mid = (l+r)/2;
    build(i<<1,l,mid);
    build((i<<1)|1,mid+1,r);
    segTree[i].val = (segTree[i<<1].val+segTree[i<<1|1].val)%mood;
}
void push_up(int i){
    segTree[i].val = max(segTree[i<<1].val,segTree[(i<<1)|1].val)%mood;
}
void push_down(int i){
    if(segTree[i].laz){
        int k = segTree[i].laz;
        segTree[i].laz = 0;
        int l = segTree[i<<1].l,r = segTree[i<<1].r;
        segTree[i<<1].laz += k;
        segTree[i<<1].val += (r-l+1)*k%mood;
        l = segTree[i<<1|1].l;
        r = segTree[i<<1|1].r;
        segTree[i<<1|1].laz += k;
        segTree[i<<1|1].val += (r-l+1)*k%mood;

    }
}
//更新线段树的第K个值为val
void update(int i,int k,int val){
    if(segTree[i].l == k && segTree[i].r == k){
        segTree[i].val = val;
        return ;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(k <= mid) update(i<<1,k,val);
    else update((i<<1)|1,k,val);
    push_up(i);
}
//从x到y结点最短路径上所有节点的值都加上z,传参 (1,p[x],p[x]+num[x]-1,z)
void update(int i,int ql,int qr,int val){
    int l = segTree[i].l,r = segTree[i].r;
    int mid = (l+r)/2;
    if(ql <= l && r <= qr){
        segTree[i].laz += val;
        segTree[i].val += (r-l+1)*val%mood;
        return ;
    }
    push_down(i);
    if(ql <= mid) update(i<<1,ql,qr,val);
    if(qr > mid) update(i<<1|1,ql,qr,val);
    segTree[i].val = (segTree[i<<1].val + segTree[i<<1|1].val)%mood;
}
//查询线段树[l,r]的最大值
int query(int i,int l,int r){
    if(segTree[i].l == l && segTree[i].r == r){
        return segTree[i].val;
    }
    int mid = (segTree[i].l + segTree[i].r)/2;
    if(r <= mid) query(i<<1,l,r);
    else if(l>mid)query((i<<1)|1,l,r);
    else return max(query(i<<1,l,mid),query((i<<1)|1,mid+1,r));
}
//查询u-->v边的最大值
int Find(int u,int v){
    int f1 = top[u],f2 = top[v];
    int tmp = 0;
    while(f1 != f2){
        if(deep[f1] < deep[f2]){
            swap(f1,f2);
            swap(v,u);
        }
        tmp = max(tmp,query(1,p[f1],p[u]));
        u = fa[f1];
        f1 = top[u];
    }
    if(u == v)  return tmp;
    if(deep[u] > deep[v]) swap(u,v);
    return max(tmp,query(1,p[son[u]],p[v]));
}
//求以x为根节点的子树内所有节点值之和 传参 (1,p[x],p[x]+num[x]-1)
int querysegTree(int i,int ql,int qr){
    int l = segTree[i].l,r = segTree[i].r;
    int mid = (l+r)/2;
    int ans=0;
    if(ql <= l && r <= qr) return segTree[i].val;
    push_down(i);
    if(ql <= mid) ans += querysegTree(i<<1,ql,qr)%mood;
    if(qr > mid) ans+=querysegTree(i<<1|1,ql,qr)%mood;
    return ans%mood;
}

void solve1(int x,int y,int z){
    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x,y);
        update(1,p[top[x]],p[x],z);
        x = fa[top[x]];
    }
    if(deep[x] > deep[y]) swap(x,y);
    update(1,p[x],p[y],z);
}
int solve2(int x,int y){
    int ans = 0;
    while(top[x] != top[y]){
        if(deep[top[x]] < deep[top[y]]) swap(x,y);
        ans += querysegTree(1,p[top[x]],p[x])%mood;
        x = fa[top[x]];
    }
    if(deep[x] > deep[y]) swap(x,y);
    ans += querysegTree(1,p[x],p[y])%mood;
    return ans%mood;
}
void solve3(int x,int z){
    update(1,p[x],num[x]+p[x]-1,z);
}
int solve4(int x){
    return querysegTree(1,p[x],num[x]+p[x]-1)%mood;
}
int main(){
    int n,m,r;
    while(~scanf("%d %d %d %d",&n,&m,&r,&mood)){
        init();
        for(int i = 1;i <= n;i++){
            scanf("%d",&a[i]);
        }
        for(int i = 1; i < n;i++){
            int u,v;
            scanf("%d %d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        dfs1(r,0,1);
        getpos(r,r);
        build(1,1,n);
        for(int i = 0;i < m;i++){
            int q,x,y,z;
            scanf("%d",&q);
            if(q == 1){
                scanf("%d %d %d",&x,&y,&z);
                solve1(x,y,z);
            }else if(q == 2){
                scanf("%d%d",&x,&y);
                printf("%d\n",solve2(x,y));
            }else if(q == 3){
                scanf("%d%d",&x,&z);
                solve3(x,z);
            }else{
                scanf("%d",&x);
                printf("%d\n",solve4(x));
            }
        }
    }
    return 0;
}



//树状数组
/*
int lowbit(int x){
    return x&(-x);
}
int c[MAXN];
int n;
int sum(int i){
    int s = 0;
    while(i > 0){
        s += c[i];
        i -=lowbit(i);
    }
    return s;
}
void add(int i,int val){
    while(i <= n){
        c[i] += val;
        i += lowbit(i);
    }
}
//u-->v 的路径上点的纸改变 val
void Change(int u,int v,int val){
    int f1 = top[u], f2 = top[v];
    int tmp = 0;
    while(f1 != f2){
        if(deep[f1] < deep[f2]){
            swap(f1,f2);
            swap(u,v);
        }
        add(p[f1],val);
        add(p[u]+1,-val);
        u = fa[f1];
        f1 = top[u];
    }
    if(deep[u] > deep[v])
        swap(u,v);
    add(p[u],val);
    add(p[v]+1,-val);
}
int a[MAXN];
*/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容