我写的是 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. rabbitmq之后台管理和用户设置(三)

    前言 前面介绍了erlang环境的安装和rabbitmq环境安装,接下来介绍rabbitmq的web管理和用户设置. 启用后台管理插件 通过后台管理插件我们可以动态监控mq的流量,创建用户,队列等. ...

  2. Nginx常见错误与问题之解决方法技术指南

      Nginx常见错误与问题之解决方法技术指南. 安装环境: 系统环境:redhat enterprise 6.5 64bit 1.Nginx 常见启动错误 有的时候初次安装nginx的时候会报这样的 ...

  3. iframe内部刷新后跳转锚点

    开发过程中需要在iframe内容页中点击刷新按钮刷新页面并跳转至页面底部,编写js函数在url后面加上锚点名称#mao,但发现并未达到预期效果,通过测试发现锚点只有在第一次访问页面的时候才会生效,所有 ...

  4. mac上安装完成node,就升级好了npm,之后的设置

    1.打开终端输入: npm config list 找到npmrc globalconfig /usr/local/etc/npmrc 2.打开npmrc sudo vim /usr/local/et ...

  5. 【转】http_load压力测试过程和使用方式

    介绍:http_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把客户机搞死.还可以测试HTTPS类的网站请求. ...

  6. java基础65 JavaScript中的Window对象(网页知识)

    1.javaScript组成部分 1.EMCAScript(基本语法)    2.BOM(Browser Object Model):浏览器对象模型            浏览器对象模型中的浏览器的各 ...

  7. TIAGo ROS模拟教程2 - 自主机器人导航

    TIAGo ROS Simulation Tutorial 2 – Autonomous robot navigation TIAGo ROS模拟教程2 - 自主机器人导航 发表于 12月 23,20 ...

  8. JDK安装及配置 (tar.gz版)和tomcat的安装

    jdk下载: 我们这里下载了jdk-8u65-linux-x64.tar.gz. 官网:http://www.oracle.com/technetwork/java/javase/downloads/ ...

  9. SCTF 2015 pwn试题分析

    Re1 是一个简单的字符串加密.程序使用了多个线程,然后进行同步.等加密线程加密好了之后才会启动验证线程.这个题比较坑的是IDA F5出来的结果不对,不知道是不是混淆机制. 刚开始看的是F5后的伪代码 ...

  10. 标准C++中的String类的使用

    要使用标准C++中的String类,必须包含#include<string>(注意不是<string.h>带.h的是C语言中的头文件) 作者:耑新新,发布于  博客园 转载请注 ...