我写的是 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. 我应该记录一下我不太了解的一些c语言函数

    当然,现在还不分类 fmemopen getpagesize()

  2. Office DDE漏洞学习笔记

    1.前言 2017年下半年爆发出来的Office漏洞,一直没有空做笔记记录.在病毒分析中也看到有利用这个漏洞的样本,针对Office系列软件发起的钓鱼攻击和APT攻击一直是安全攻防的热点. 2.off ...

  3. MVC中检测到有潜在危险的 Request.Form 值

    在做mvc项目时,当使用xhedit or.ueditor编辑器时,点击提交时,编辑器中的内容会带有html标签提交给服务器,这时就是会报错,出现如下内容: “/”应用程序中的服务器错误. 从客户端( ...

  4. Linux输入子系统:多点触控协议 -- multi-touch-protocol.txt【转】

    转自:http://blog.csdn.net/droidphone/article/details/8434768 Multi-touch (MT) Protocol --------------- ...

  5. linux音频alsa-uda134x驱动文档阅读之一转自http://blog.csdn.net/wantianpei/article/details/7817293

    前言 目前,linux系统常用的音频驱动有两种形式:alsa oss alsa:现在是linux下音频驱动的主要形式,与简单的oss兼容.oss:过去的形式而我们板子上的uda1341用的就是alsa ...

  6. asp.net操作word 配置在IIS上出现的问题

    异常: 检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件失败,原因是出现以下错误: 80070005 拒绝访问. (异常来自 ...

  7. clog,cout,cerr 输出机制

    clog:控制输出,使其输出到一个缓冲区,这个缓冲区关联着定义在 <cstdio> 的 stderr. cerr:强制输出刷新,没有缓冲区. cout:控制输出,使其输出到一个缓冲区,这个 ...

  8. centos6.9系统优化

    仅供参考 有道云笔记链接->

  9. 【web开发】web前端开发常用技术总结归纳

    技术选型规范规范 • Vue版本:2.x • 前端路由:vue-route • 异步请求:Axios • 全局状态管理:VueX • css预处理器:sass/less • h5项目移动端适配规则:使 ...

  10. git —— 基本命令以及操作(No.1)

    git基本命令(附加描述) 1.把文件添加到暂存区$ git add readme.txt 2.把暂存区的文件文件添加到仓库$ git commit -m "提交说明" 备注:ad ...