bzoj 4034
我写的是 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的更多相关文章
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- [BZOJ 4034] 树上操作
Link: BZOJ 4034 传送门 Solution: 树剖模板题…… Code: #include <bits/stdc++.h> using namespace std; type ...
- bzoj 4034 [HAOI2015] T2(树链剖分,线段树)
4034: [HAOI2015]T2 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1536 Solved: 508[Submit][Status] ...
- Bzoj 4034: [HAOI2015]T2 树链剖分,子树问题,dfs序
4034: [HAOI2015]T2 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1841 Solved: 598[Submit][Status] ...
- BZOJ 4034 [HAOI2015]T2(树链剖分)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4034 [题目大意] 有一棵点数为 N 的树,以点 1 为根,且树点有边权. 有 M 个 ...
- BZOJ 4034: [HAOI2015]T2( 树链剖分 )
树链剖分...子树的树链剖分序必定是一段区间 , 先记录一下就好了 ------------------------------------------------------------------ ...
- bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4352 Solved: 1387[Submit][Stat ...
- bzoj 4034: [HAOI2015]树上操作 (树剖+线段树 子树操作)
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6779 Solved: 2275[Submit][Stat ...
- bzoj 4034: [HAOI2015]T2
4034: [HAOI2015]T2 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操 ...
随机推荐
- 使用idea的的第一个坑-----javax.xml.ws.WebServiceRef
新建项目启动报错的时候,一直报这个错,类找不到,郁闷了半天,都没百度到结果,后来发现是添加tomcat的时候jre没 指定..... 哈哈哈,太懵逼了,指定就ok了
- 【四校联考】【比赛题解】FJ NOIP 四校联考 2017 Round 7
此次比赛为厦门一中出题.都是聚劳,不敢恭维. 莫名爆了个0,究其原因,竟然是快读炸了……很狗,很难受. 话不多说,来看看题: [T1] 题意: 样例: PS:1<=h[i]<=100000 ...
- nginx_upstream_check_module-master对nginx的后端机器进行健康状态检查报403错误【转】
在nginx.conf配置文件中 在server添加 location /nstatus { check_status; access_log off; #allow 192.168.2.11; #d ...
- 基于vue配置axios
转载地址:https://juejin.im/post/5a02a898f265da43052e0c85 1.背景 在项目开发中ajax请求是必不可缺少 一部分ajax请求不需要loading或则请求 ...
- jmeter之数据库
https://www.cnblogs.com/ShadowXie/p/6007515.html
- 洛谷P1841重要的城市
传送门啦 重要城市有三个性质如下: 1.重要城市能对其他两个不同城市的最短路径做出贡献 2.重要城市具有唯一性,如果两不同城市之间的最短路径有两种中间城市情况,那么这两个中间城市可以彼此代替,就都不能 ...
- SQL2008数据库导出到SQL2000全部步骤过程
2008转到2000的步骤 1. 在sql2008上生成for 2000版本的数据库脚本 -- 打开"对象资源管理器"(没有的话按F8), 连接到你的实例, 右键要转到2000的库 ...
- Java工程师知识图谱
一.Java工程师知识图谱(思维导图版) 二.Java工程师知识图谱(图文版) 三.Java工程师知识图谱(文字版) http://note.youdao.com/noteshare?id=615da ...
- Python中super的应用
约定 单继承 多继承 super 是个类 多继承中 super 的工作方式 参考资料 约定 在开始之前我们来约定一下本文所使用的 Python 版本.默认用的是 Python 3,也就是说:本文所定义 ...
- strings.xml显示html格式
需求:合同协议,其中指定内容为红色 效果图: 实现如下: <string name="learn_ticket_agreement" formatted="fals ...