cogs 1963. [HAOI 2015] 树上操作 树链剖分+线段树

1963. [HAOI 2015] 树上操作

★★★☆   输入文件:haoi2015_t2.in   输出文件:haoi2015_t2.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

有一棵点数为N的树,以点1为根,且树点有权值。然后有M个操作,分为三种:

操作1:把某个节点x的点权增加a。

操作2:把某个节点x为根的子树中所有点的点权都增加a。

操作3:询问某个节点x到根的路径中所有点的点权和。

【输入格式】

第一行两个整数N,M,表示点数和操作数。

接下来一行N个整数,表示树中节点的初始权值。

接下来N-1行每行两个正整数fr,to,表示该树中存在一条边(fr,to)。

再接下来M行,每行分别表示一次操作。其中第一个数表示该操作的种类(1~3),之后接这个操作的参数(x或者x a)。

【输出格式】

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

【样例输入】

5 5

1 2 3 4 5

1 2

1 4

2 3

2 5

3 3

1 2 1

3 5

2 1 2

3 3

【样例输出】

6

9

13

【提示】

对于30%的数据,N,M<=1000

对于50%的数据,N,M<=100000且数据随机。

对于100%的数据,N,M<=100000,且所有输入数据的绝对值都不会超过10^6。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
#define LL long long
const int maxn=100005;
int n,m,cot=0;
LL a[maxn];
vector<int> v[maxn];
int size[maxn];
int son[maxn];
int fa[maxn];
int top[maxn];
int dfn[maxn];
int pos[maxn];
int dep[maxn];
int en[maxn];
LL ls[maxn<<1],rs[maxn<<1],lz[maxn<<1],sum[maxn<<1];
int cnt=0;
void Dfs(int rt){
    size[rt]=1;
    for(int i=0;i<v[rt].size();i++)
        if(!size[v[rt][i]]){
            int to=v[rt][i];
            dep[to]=dep[rt]+1;
            fa[to]=rt;
            Dfs(to);
            size[rt]+=size[to];
            if(size[son[rt]]<size[to]) son[rt]=to;
        }
}
void Dfs(int rt,int tp){
    top[rt]=tp;
    dfn[++cnt]=rt;
    pos[rt]=cnt;
    if(son[rt]) Dfs(son[rt],tp);
    for(int i=0;i<v[rt].size();i++)
        if(!top[v[rt][i]])
            Dfs(v[rt][i],v[rt][i]);
    en[rt]=cnt;
}
int Build(int l,int r){
    int rt=++cot;
    if(l==r){
        sum[rt]=a[dfn[l]];
        return rt;
    }
    int mid=(l+r)>>1;
    ls[rt]=Build(l,mid);
    rs[rt]=Build(mid+1,r);
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
    return rt;
}
void Push_down(int rt,int l,int r){
    int mid=(l+r)>>1;
    lz[ls[rt]]+=lz[rt];
    lz[rs[rt]]+=lz[rt];
    sum[ls[rt]]+=lz[rt]*(mid-l+1);
    sum[rs[rt]]+=lz[rt]*(r-mid);
    lz[rt]=0;

}
LL Add(int rt,int l,int r,int s,int t,int qx){
    if(s>r||t<l)     return 0;
    if(s<=l&&r<=t){
        sum[rt]+=qx*1ll*(r-l+1);
        lz[rt]+=qx;
        return 0;
    }
    Push_down(rt,l,r);
    int mid=(l+r)>>1;
    Add(ls[rt],l,mid,s,t,qx);Add(rs[rt],mid+1,r,s,t,qx);
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
LL Sum(int rt,int l,int r,int s,int t){
    if(s>r||t<l) return 0;
    if(s<=l&&r<=t) return sum[rt];
    Push_down(rt,l,r);
    int mid=(l+r)>>1;
    return Sum(ls[rt],l,mid,s,t)+Sum(rs[rt],mid+1,r,s,t);
}
LL LCA_dis(int x,int y){
    LL res=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        res+=Sum(1,1,n,pos[top[x]],pos[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    res+=Sum(1,1,n,pos[x],pos[y]);
    return res;
}
int main()
{
    freopen("haoi2015_t2.in","r",stdin);
    freopen("haoi2015_t2.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for(int i=1;i<n;i++) {
        int x,y;scanf("%d%d",&x,&y);
        v[x].push_back(y);v[y].push_back(x);
    }
    Dfs(1);Dfs(1,1);Build(1,n);
    while(m--){
        int opt;scanf("%d",&opt);
        if(opt==1){
            int x,aa;scanf("%d%d",&x,&aa);
            Add(1,1,n,pos[x],pos[x],aa);
        }
        if(opt==2){
            int x,aa;
            scanf("%d%d",&x,&aa);
            Add(1,1,n,pos[x],en[x],aa);
        }
        if(opt==3){
            int x;scanf("%d",&x);
            printf("%lld\n",LCA_dis(x,1));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Tidoblogs/p/11317909.html

时间: 2024-11-09 12:27:01

cogs 1963. [HAOI 2015] 树上操作 树链剖分+线段树的相关文章

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分+线段树区间合并

题目描述 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号 排名.由乃会按照心情对这些用户做以下四种操作,修改用户的排名和编号:然而由乃心情非常不好,因为Deus天 天问她题...因为Deus天天问由乃OI题,所以由乃去学习了一下OI,由于由乃智商挺高,所以OI学的特别熟练她 在RBOI2016中以第一名的成绩进入省队,参加了NOI2016获得了金牌保送 Deus:这个题怎么做呀? yuno:这个不是NOI2014的水题吗... Deu

【POJ3237】Tree(树链剖分+线段树)

Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 throughN − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions

HDU-3966 Aragorn&#39;s Story(树链剖分+线段树)

Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 12479    Accepted Submission(s): 3331 Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lor

hdu3966 树链剖分+线段树 裸题

HDU - 3966 题意:给一颗树,3种操作,Q u 查询u节点的权值,I a b c 对a到b的路径上每个点的点权增加c,D a b c 对a b 路径上所有点的点权减少c 思路:树链剖分+线段树,2个问题,第一,如果是先建树再输入点的点权,记录tip(点映射到线段树后的位置),如果先输入点权,再建树,不仅要记录tip还要记录ran(线段树上某个位置上的点对应的树上点的序号,与tip是相互映射):第二,连接起线段树和树链剖分的是get函数,区间操作才需要用到get函数,单点操作直接在线段树上

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl