刷个清新的数据结构题爽一爽?

题意:

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
 
注意到操作3,询问x到根的路径之间点权和,容易发现这就是欧拉序列中的前缀和。
所以按照树的欧拉序列建线段树,然后操作1就变成单点修改,操作2,就变成了区间内某些点+a,某些点-a,也容易用tag标记进行维护。
 
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <bitset>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-
# define MOD
# define INF
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<,l,mid
# define rch p<<|,mid+,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int N=;
//Code begin... struct Seg{LL sum, tag; int p;}seg[N<<];
struct Edge{int p, next;}edge[N<<];
int head[N], cnt=, node[N], pos, fdfs[N][];
struct DFN{int id; bool flag;}dfn[N<<]; void add_edge(int u, int v){edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++;}
void dfs(int x, int fa){
dfn[++pos].id=x; dfn[pos].flag=true; fdfs[x][]=pos;
for (int i=head[x]; i; i=edge[i].next) {
int v=edge[i].p;
if (v==fa) continue;
dfs(v,x);
}
dfn[++pos].id=x; dfn[pos].flag=false; fdfs[x][]=pos;
}
void push_up(int p){seg[p].p=seg[p<<].p+seg[p<<|].p; seg[p].sum=seg[p<<].sum+seg[p<<|].sum;}
void push_down(int p, int L){
if (!seg[p].tag) return ;
seg[p].sum+=(LL)(*seg[p].p-L)*seg[p].tag;
seg[p<<].tag+=seg[p].tag; seg[p<<|].tag+=seg[p].tag; seg[p].tag=;
}
void init(int p, int l, int r){
if (l<r) {
int mid=(l+r)>>;
init(lch); init(rch); push_up(p);
}
else {
seg[p].sum=dfn[l].flag?node[dfn[l].id]:-node[dfn[l].id];
seg[p].p=dfn[l].flag;
}
}
LL query(int p, int l, int r, int R){
push_down(p,r-l+);
if (R<l) return ;
if (R>=r) return seg[p].sum;
int mid=(l+r)>>;
return query(lch,R)+query(rch,R);
}
void update1(int p, int l, int r, int X, int val){
push_down(p,r-l+);
if (X<l||X>r) return ;
if (X==l&&X==r) seg[p].sum+=val;
else {
int mid=(l+r)>>;
update1(lch,X,val); update1(rch,X,val); push_up(p);
}
}
void update2(int p, int l, int r, int L, int R, int val){
push_down(p,r-l+);
if (L>r||R<l) return ;
if (L<=l&&R>=r) seg[p].tag+=val, push_down(p,r-l+);
else {
int mid=(l+r)>>;
update2(lch,L,R,val); update2(rch,L,R,val); push_up(p);
}
}
int main ()
{
int n, m, flag, u, v;
scanf("%d%d",&n,&m);
FOR(i,,n) scanf("%d",node+i);
FO(i,,n) scanf("%d%d",&u,&v), add_edge(u,v), add_edge(v,u);
dfs(,);
init(,,n<<);
while (m--) {
scanf("%d%d",&flag,&u);
if (flag==) printf("%lld\n",query(,,n<<,fdfs[u][]));
else {
scanf("%d",&v);
if (flag==) update1(,,n<<,fdfs[u][],v), update1(,,n<<,fdfs[u][],-v);
else update2(,,n<<,fdfs[u][],fdfs[u][],v);
}
}
return ;
}

BZOJ 4034 树上操作(树的欧拉序列+线段树)的更多相关文章

  1. BZOJ 4034: [HAOI2015]树上操作 [欧拉序列 线段树]

    题意: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 显然树链剖分可做 ...

  2. BZOJ 4034 [HAOI2015]树上操作(欧拉序+线段树)

    题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增 ...

  3. BZOJ 4034"树上操作"(DFS序+线段树)

    传送门 •题意 有一棵点数为 N 的树,以点 1 为根,且树点有边权. 然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的 ...

  4. HDU 4836 The Query on the Tree lca || 欧拉序列 || 动态树

    lca的做法还是非常明显的.简单粗暴, 只是不是正解.假设树是长链就会跪,直接变成O(n).. 最后跑的也挺快,出题人还是挺阳光的.. 动态树的解法也是听别人说能ac的.预计就是放在splay上剖分一 ...

  5. [BZOJ 4034] 树上操作

    Link: BZOJ 4034 传送门 Solution: 树剖模板题…… Code: #include <bits/stdc++.h> using namespace std; type ...

  6. LOJ #2142. 「SHOI2017」相逢是问候(欧拉函数 + 线段树)

    题意 给出一个长度为 \(n\) 的序列 \(\{a_i\}\) 以及一个数 \(p\) ,现在有 \(m\) 次操作,每次操作将 \([l, r]\) 区间内的 \(a_i\) 变成 \(c^{a_ ...

  7. LightOJ 1370 Bi-shoe and Phi-shoe 欧拉函数+线段树

    分析:对于每个数,找到欧拉函数值大于它的,且标号最小的,预处理欧拉函数,然后按值建线段树就可以了 #include <iostream> #include <stdio.h> ...

  8. loj1370(欧拉函数+线段树)

    传送门:Bi-shoe and Phi-shoe 题意:给出多个n(1<=n<=1e6),求满足phi(x)>=n的最小的x之和. 分析:先预处理出1~1e6的欧拉函数,然后建立一颗 ...

  9. [LNOI] 相逢是问候 || 扩展欧拉函数+线段树

    原题为2017六省联考的D1T3 给出一个序列,m次操作,模数p和参数c 操作分为两种: 1.将[l,r]区间内的每个数x变为\(c^x\) 2.求[l,r]区间内数的和%p 首先,我们要了解一些数论 ...

随机推荐

  1. 20155325实验四 Android程序设计

    实验四 Android程序设计-1 Android Stuidio的安装测试: 参考<Java和Android开发学习指南(第二版)(EPUBIT,Java for Android 2nd)&g ...

  2. Ubuntu genymotion

    官网注册帐号 下载genymotion-[VERSION]_[ARCH].bin 进入android studio In Android Studio, go to File > Setting ...

  3. WPF DrawingContext Pen

    <Window x:Class="WPFDrawing.MainWindow" xmlns="http://schemas.microsoft.com/winfx/ ...

  4. [深度学习] 使用Darknet YOLO 模型破解中文验证码点击识别

    内容 背景 准备 实践 结果 总结 引用 背景 老规矩,先上代码吧 代码所在: https://github.com/BruceDone/darknet_demo 最近在做深度学习相关的项目的时候,了 ...

  5. selenium webdriver API详解(二)

    本系列主要讲解webdriver常用的API使用方法(注意:使用前请确认环境是否安装成功,浏览器驱动是否与谷歌浏览器版本对应) 一:获取当前页面的title(一般获取title用于断言) from s ...

  6. JMeter自学笔记1-环境安装

    一.写在前面的话: Jmeter是一款优秀的开源测试工具, 是每位测试工程师进阶过程中,需要熟悉并掌握的一款测试工具,熟练使用Jmeter能大大提高工作效率. Jmeter环境安装需要依赖JDK,所以 ...

  7. JAVA Date、String、Calendar类型之间的转化

    1.Calendar 转化 String //获取当前时间的具体情况,如年,月,日,week,date,分,秒等 Calendar calendat = Calendar.getInstance(); ...

  8. 日本IT行业劳动力缺口达22万 在日中国留学生迎来就业好时机 2017/07/18 11:25:09

    作者:倪亚敏 来源:日本新华侨报 发布时间:2017/07/18 11:25:09     据日本政府提供的数据,日本2018年应届毕业生的“求人倍率”已经达到了1.78倍.换言之,就是100名大学生 ...

  9. 1.airflow的安装

    1.环境准备1.1 安装环境1.2 创建用户2.安装airflow2.1 安装python2.2 安装pip2.3 安装数据库2.4 安装airflow2.4.1 安装主模块2.4.2 安装数据库模块 ...

  10. curl和file_get_contents 区别以及各自的优劣

    PHP中fopen,file_get_contents,curl函数的区别: 1.fopen /file_get_contents 每次请求都会重新做DNS查询,并不对 DNS信息进行缓存.但是CUR ...