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 . 操 ...
随机推荐
- centos 安装memcache服务后memcahce本机连接Permission
自己手动在虚拟机下装了下memcache,整个过程真是充满波折,本身用php5.3安装memcache扩展就麻烦很多,无法通过yum直接安装,安装方法详见http://chenwei.me/blog/ ...
- java 多线程 Future callable
面向对象5大设计原则 1.单一职责原则 一个类只包含它相关的方法,增删改查.一个方法只包含单一的功能,增加.一个类最多包含10个方法,一个方法最多50行,一个类最多500行.重复的代码进行封装,Do ...
- Java不为人知的小秘密
Java中的main方法必须有一个外壳类,而且必须是静态的! Java中的所有函数都属于某个类的方法,所以main方法也不例外,必须放在一个类中才能编译运行. 例如: public class tex ...
- 十二、springcloud之展示追踪数据 Sleuth+zipkin
一.Zipkin简介 Zipkin是Twitter的一个开源项目,它基于Google Dapper实现.我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API接口来辅助我们 ...
- 微软Holographic将更名为Windows Mixed Reality
微软Holographic将更名为Windows Mixed Reality ----世界变化好快. 还没来得及细细品味,它就已经更名了. 程序员的焦虑,处在一个信息大爆炸的年代,大数据,云计算,机 ...
- Scrapy官网程序执行示例
Windows 10家庭中文版本,Python 3.6.4,Scrapy 1.5.0, Scrapy已经安装很久了,前面也看了不少Scrapy的资料,自己尝试使其抓取微博的数据时,居然连登录页面(首页 ...
- 使用dos命令创建多模块Maven项目
好吧,咱们接着上一篇博客继续用另一种方式来创建Maven项目.不过在创建之前我们应该先熟悉一些相关dos命令. 创建web项目命令: mvn archetype:generate -DgroupId= ...
- Java与redis交互、Jedis连接池JedisPool
Java与redis交互比较常用的是Jedis. 先导入jar包: commons-pool2-2.3.jar jedis-2.7.0.jar 基本使用: public class RedisTest ...
- 配置toad远程连接oracle
在oracle服务器上: C:\app\Administrator\product\11.2.0\dbhome_1\NETWORK\ADMIN目录 文件:listener.ora(10.144.118 ...
- 【LOJ】#2047. 「CQOI2016」伪光滑数
题解 可持久化可并堆 用\(f[i,j]\)表示最大的质数标号为i,然后有j个质数乘起来 用\(g[i,j]\)表示\(\sum_{k = 1}^{i}f[k,j]\) 转移是 \(f[i,j] = ...