我写的是 DFS序+线段树

DFS序(出去的位置要单独建点)上,进入的位置是权值,出去的位置是权值的相反数,可以证明节点i到根节点的路径上的点的权值和是DFS序上1~in[i]的和。

只要搞出每个区间的进入位置和出去位置的和,就可以打标记了。

 /**************************************************************
Problem: 4034
User: idy002
Language: C++
Result: Accepted
Time:2748 ms
Memory:26616 kb
****************************************************************/ #include <cstdio>
#include <cstdlib>
#define fprintf(...)
#define N 100010 typedef long long dnt;
struct Node {
dnt s, tag;
int tc[];
Node *ls, *rs;
}pool[N*], *tail=pool, *root; int n, m;
int head[N], dest[N+N], next[N+N], etot;
int in[N], out[N], type[N+N], ww[N], sww[N+N], idc;
bool vis[N]; Node *build( int lf, int rg ) {
Node *nd = ++tail;
if( lf==rg ) {
nd->s = sww[lf];
nd->tc[type[lf]]=;
nd->tc[type[lf]^]=;
return nd;
}
int mid=(lf+rg)>>;
nd->ls = build( lf, mid );
nd->rs = build( mid+, rg );
nd->tc[] = nd->ls->tc[] + nd->rs->tc[];
nd->tc[] = nd->ls->tc[] + nd->rs->tc[];
nd->s = nd->ls->s + nd->rs->s;
fprintf( stderr, "[%d,%d] tc[0]=%d tc[1]=%d\n", lf, rg, nd->tc[], nd->tc[] );
return nd;
}
inline void pushdown( Node *nd ) {
if( nd->tag ) {
nd->ls->s += nd->ls->tc[]*nd->tag - nd->ls->tc[]*nd->tag;
nd->rs->s += nd->rs->tc[]*nd->tag - nd->rs->tc[]*nd->tag;
nd->ls->tag += nd->tag;
nd->rs->tag += nd->tag;
nd->tag = ;
}
}
inline void update( Node *nd ) {
nd->s = nd->ls->s + nd->rs->s;
}
void modify( Node *nd, int lf, int rg, int L, int R, dnt delta ) {
if( L<=lf && rg<=R ) {
nd->s += nd->tc[]*delta - nd->tc[]*delta;
nd->tag += delta;
return;
}
int mid=(lf+rg)>>;
pushdown(nd);
if( L<=mid ) modify( nd->ls, lf, mid, L, R, delta );
if( R>mid ) modify( nd->rs, mid+, rg, L, R, delta );
update( nd );
}
dnt query( Node *nd, int lf, int rg, int L, int R ) {
if( L<=lf && rg<=R ) {
fprintf( stderr, "( %d %d ) = %lld\n", lf, rg, nd->s );
return nd->s;
}
int mid=(lf+rg)>>;
pushdown(nd);
dnt rt = ;
if( L<=mid ) rt += query( nd->ls, lf, mid, L, R );
if( R>mid ) rt += query( nd->rs, mid+, rg, L, R );
update(nd);
return rt;
}
void adde( int u, int v ) {
etot++;
next[etot] = head[u];
dest[etot] = v;
head[u] = etot;
}
void dfs( int u, int fa ) {
if( vis[u] ) {
exit();
return;
}
vis[u] = true;
idc++;
in[u] = idc;
type[idc] = ;
sww[idc] = ww[u];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fa ) continue;
dfs(v,u);
}
idc++;
out[u] = idc;
type[idc] = ;
sww[idc] = -ww[u];
}
void mdf_sig( int u, int a ) {
modify( root, , idc, in[u], in[u], +a );
modify( root, , idc, out[u], out[u], +a );
fprintf( stderr, "modify( %d %d %d )\n", in[u], in[u], +a );
fprintf( stderr, "modify( %d %d %d )\n", out[u], out[u], +a );
}
void mdf_sub( int u, int a ) {
modify( root, , idc, in[u], out[u], +a );
fprintf( stderr, "modify( %d %d %d )\n", in[u], out[u], +a );
}
dnt query( int u ) {
dnt rt = query( root, , idc, , in[u] );
fprintf( stderr, "query( %d %d ) = %lld\n", , in[u], rt );
return rt;
}
int main() {
scanf( "%d%d", &n, &m );
for( int i=; i<=n; i++ )
scanf( "%d", ww+i );
for( int i=,u,v; i<n; i++ ) {
scanf( "%d%d", &u, &v );
adde( u, v );
adde( v, u );
}
fprintf( stderr, "dfs(...)\n" );
dfs(,);
fprintf( stderr, "\n" );
fprintf( stderr, "build(...)\n" );
root = build( , idc );
for( int t=; t<m; t++ ) {
int opt, u, a;
scanf( "%d", &opt );
fprintf( stderr, "%d\n", opt );
if( opt== ) {
scanf( "%d%d", &u, &a );
mdf_sig( u, a );
} else if( opt== ) {
scanf( "%d%d", &u, &a );
mdf_sub( u, a );
} else {
scanf( "%d", &u );
printf( "%lld\n", query(u) );
}
}
}

还有一种做法:链剖

以前一直以为链剖只能用于链修改和链查询。。。。

其实,链剖是一种特殊的DFS序,它合理地安排了DFS的顺序(先重儿子,再轻儿子),让我们可以把任意一条路径映射为O(logn)条连续的线段,然后就可以做很多问题了。

其次是和子树相关的问题,我们一般是把DFS序弄出来,然后一个子树就是连续的一段,这样实现子树相关的操作。

我们把两个结合起来就可以做到:链修改与查询+子树修改与查询。

(好像还有一种链剖解决子树问题的方法,就是每个节点再记录所有轻边代表的子树的信息)。

 #include <cstdio>
#include <cstdlib>
#define fprintf(...)
#define N 100010 typedef long long dnt;
struct Node {
dnt s, tag;
int tc[];
Node *ls, *rs;
}pool[N*], *tail=pool, *root; int n, m;
int head[N], dest[N+N], next[N+N], etot;
int in[N], out[N], type[N+N], ww[N], sww[N+N], idc;
bool vis[N]; Node *build( int lf, int rg ) {
Node *nd = ++tail;
if( lf==rg ) {
nd->s = sww[lf];
nd->tc[type[lf]]=;
nd->tc[type[lf]^]=;
return nd;
}
int mid=(lf+rg)>>;
nd->ls = build( lf, mid );
nd->rs = build( mid+, rg );
nd->tc[] = nd->ls->tc[] + nd->rs->tc[];
nd->tc[] = nd->ls->tc[] + nd->rs->tc[];
nd->s = nd->ls->s + nd->rs->s;
fprintf( stderr, "[%d,%d] tc[0]=%d tc[1]=%d\n", lf, rg, nd->tc[], nd->tc[] );
return nd;
}
inline void pushdown( Node *nd ) {
if( nd->tag ) {
nd->ls->s += nd->ls->tc[]*nd->tag - nd->ls->tc[]*nd->tag;
nd->rs->s += nd->rs->tc[]*nd->tag - nd->rs->tc[]*nd->tag;
nd->ls->tag += nd->tag;
nd->rs->tag += nd->tag;
nd->tag = ;
}
}
inline void update( Node *nd ) {
nd->s = nd->ls->s + nd->rs->s;
}
void modify( Node *nd, int lf, int rg, int L, int R, dnt delta ) {
if( L<=lf && rg<=R ) {
nd->s += nd->tc[]*delta - nd->tc[]*delta;
nd->tag += delta;
return;
}
int mid=(lf+rg)>>;
pushdown(nd);
if( L<=mid ) modify( nd->ls, lf, mid, L, R, delta );
if( R>mid ) modify( nd->rs, mid+, rg, L, R, delta );
update( nd );
}
dnt query( Node *nd, int lf, int rg, int L, int R ) {
if( L<=lf && rg<=R ) {
fprintf( stderr, "( %d %d ) = %lld\n", lf, rg, nd->s );
return nd->s;
}
int mid=(lf+rg)>>;
pushdown(nd);
dnt rt = ;
if( L<=mid ) rt += query( nd->ls, lf, mid, L, R );
if( R>mid ) rt += query( nd->rs, mid+, rg, L, R );
update(nd);
return rt;
}
void adde( int u, int v ) {
etot++;
next[etot] = head[u];
dest[etot] = v;
head[u] = etot;
}
void dfs( int u, int fa ) {
if( vis[u] ) {
exit();
return;
}
vis[u] = true;
idc++;
in[u] = idc;
type[idc] = ;
sww[idc] = ww[u];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fa ) continue;
dfs(v,u);
}
idc++;
out[u] = idc;
type[idc] = ;
sww[idc] = -ww[u];
}
void mdf_sig( int u, int a ) {
modify( root, , idc, in[u], in[u], +a );
modify( root, , idc, out[u], out[u], +a );
fprintf( stderr, "modify( %d %d %d )\n", in[u], in[u], +a );
fprintf( stderr, "modify( %d %d %d )\n", out[u], out[u], +a );
}
void mdf_sub( int u, int a ) {
modify( root, , idc, in[u], out[u], +a );
fprintf( stderr, "modify( %d %d %d )\n", in[u], out[u], +a );
}
dnt query( int u ) {
dnt rt = query( root, , idc, , in[u] );
fprintf( stderr, "query( %d %d ) = %lld\n", , in[u], rt );
return rt;
}
int main() {
scanf( "%d%d", &n, &m );
for( int i=; i<=n; i++ )
scanf( "%d", ww+i );
for( int i=,u,v; i<n; i++ ) {
scanf( "%d%d", &u, &v );
adde( u, v );
adde( v, u );
}
fprintf( stderr, "dfs(...)\n" );
dfs(,);
fprintf( stderr, "\n" );
fprintf( stderr, "build(...)\n" );
root = build( , idc );
for( int t=; t<m; t++ ) {
int opt, u, a;
scanf( "%d", &opt );
fprintf( stderr, "%d\n", opt );
if( opt== ) {
scanf( "%d%d", &u, &a );
mdf_sig( u, a );
} else if( opt== ) {
scanf( "%d%d", &u, &a );
mdf_sub( u, a );
} else {
scanf( "%d", &u );
printf( "%lld\n", query(u) );
}
}
}

bzoj 4034的更多相关文章

  1. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  2. [BZOJ 4034] 树上操作

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

  3. bzoj 4034 [HAOI2015] T2(树链剖分,线段树)

    4034: [HAOI2015]T2 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1536  Solved: 508[Submit][Status] ...

  4. Bzoj 4034: [HAOI2015]T2 树链剖分,子树问题,dfs序

    4034: [HAOI2015]T2 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1841  Solved: 598[Submit][Status] ...

  5. BZOJ 4034 [HAOI2015]T2(树链剖分)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4034 [题目大意] 有一棵点数为 N 的树,以点 1 为根,且树点有边权. 有 M 个 ...

  6. BZOJ 4034: [HAOI2015]T2( 树链剖分 )

    树链剖分...子树的树链剖分序必定是一段区间 , 先记录一下就好了 ------------------------------------------------------------------ ...

  7. bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Stat ...

  8. bzoj 4034: [HAOI2015]树上操作 (树剖+线段树 子树操作)

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 6779  Solved: 2275[Submit][Stat ...

  9. bzoj 4034: [HAOI2015]T2

    4034: [HAOI2015]T2 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操 ...

随机推荐

  1. 【驱动】USB驱动实例·串口驱动·键盘驱动【转】

    转自:http://www.cnblogs.com/lcw/p/3159370.html Preface USB体系支持多种类型的设备. 在 Linux内核,所有的USB设备都使用 usb_drive ...

  2. REX系统2

    REX(Real Time Executive)是一个面向嵌入式应用的,简单高效的,抢先式,多任务实时操作系统,支持基于优先级的任务调度算法(支持优先级反转).它提供了任务控制,任务同步,互斥,定时器 ...

  3. aarch64_g4

    golang-github-inconshreveable-muxado-devel-0-0.7.gitf693c7e.fc26.noarch.rpm 2017-02-11 16:47 30K fed ...

  4. Python开发环境(1):Eclipse+PyDev插件

    电脑:小米笔记本电脑Pro 15.6寸(i5-8250U),操作系统:Windows 10,JDK版本:1.8.0_152(环境变量已配置) Step 1.下载Eclipse 根据我的CPU型号,选择 ...

  5. win10 操作配置备忘

    让程序自动启动 如果想要实现应用程序在所有的用户登录系统后都能自动启动,就把该应用程序的快捷方式放到"系统启动文件夹"里: C:\ProgramData\Microsoft\Win ...

  6. caffe+win7+vs2013 仅CPU环境安装

    笔者对深度学习一直充满着好奇与兴趣,之前学校都是研究图像处理的特征点方式,机器学习使用也不多,别提深度学习了. 在看了李宏毅大佬的PPT后,有了初步的认识,虽然是渣渣电脑,也想自己跑几个深度模型. 说 ...

  7. 在VirtualBox虚拟机中安装Centos操作系统怎么与本地XShell远程连接

    问题: 在VirtualBox安装好了CentOS操作系统后,我们怎么才可以用XSell连接虚拟机中的CentOS呢? 答案: (1)在windows下用cmd--ipconfig查看VirtualB ...

  8. python_docx制作word文档

    一.docx模块 Python可以利用python-docx模块处理word文档,处理方式是面向对象的.也就是说python-docx模块会把word文档,文档中的段落.文本.字体等都看做对象,对对象 ...

  9. OutLook中添加Exchange失败问题

    问题: 在邮件中添加账户后,打开outlook时报出错误:无法启动 Microsoft Outlook. 无法打开 Outlook 窗口. 无法打开此文件夹集合. 必须先使用当前的配置文件连接到 Mi ...

  10. Python装饰器讲解

    Python装饰器讲解 定义:本质是函数,就是为其他函数添加附加功能.原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 import time def timmer(func ...