[bzoj4034][HAOI2015]树上操作
来源:互联网 发布:专业英语翻译软件 编辑:程序博客网 时间:2024/05/17 03:31
树上操作
Description:
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input:
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output:
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
HINT:
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6
题解:
此题为一道很裸的树链剖分的题,下面来介绍一下树链剖分。
树链剖分:
树链剖分有几个基本概念:
1.重点:即相比于兄弟节点,子树节点最多的点 2.重链:重点连成的链 树链剖分就是剖分出重链,然后把重链连在一起, 再用数据结构来维护重链.
剖分重链有很多办法,这里我介绍两次DFS的方法.
由于涉及到的数组多,我先解释一下它们各自的含义:
top[i] i节点所在重链的起点
siz[i] i节点的大小(子节点个数)
fat[i] i节点的父亲节点
son[i] i节点的中儿子
in[i] i节点在dfs中第一次访问的次序
out[i] i节点在dfs中回溯的次序
void dfs_1( int x ){ siz[x] = 1; for ( int i = head[x]; i; i = next[i]) if ( to[i] != fat[x] ){ int v = to[i]; dep[v] = dep[u] + 1; fat[v] = x; dfs_1( v ); siz[x] += siz[v]; }}
第一遍DFS求出fat[], siz[], dep[]的值,很好理解,这里不过多交代。
void dfs_2( int x, int tp ){ top[x] = tq; in[x] = ++id; int k = 0; for ( int i = head[x]; i; i = next[i]) if ( to[i] != fa[x] && siz[ to[i] ] > siz[k] ) k = to[i]; if ( k ){ dfs_2( k, tq ); } for ( int i = head[x]; i; i = next[i]) if ( to[i] != fat[x] && to[i] != k ){ int v = to[i]; dfs_2( v, v ); } out[x] = id;}
第二次DFS根据前面算出的siz[]来找中儿子,即代码中的k,在用时间戳id求出in[]和out[].
这道题用DFS剖出重链以后,再用线段树维护in[],线段树要提供区间求和、区间加减的功能。
/************************************************************** Problem: 4034 User: Venishel Language: C++ Result: Accepted Time:2760 ms Memory:16456 kb****************************************************************/#include <cstdio>#include <iostream>#include <cstring>using namespace std;const int N = 1e5 + 7;#define LL long longstruct Edge{ int nxt, to;}e[N<<1];int head[N], tot=0;void addeage(int u, int v){ e[++tot].nxt=head[u], e[tot].to=v; head[u]=tot;}int sz[N], mx[N], pos[N], fat[N], v[N], bl[N];int id=0, n, m;void dfs1(int u, int fa){ sz[u]=1; for ( int i=head[u]; i; i=e[i].nxt ){ int v=e[i].to; if( v==fa ) continue; fat[v]=u; dfs1(v, u); sz[u]+=sz[v]; }}void dfs2(int u, int fa, int fq){ bl[u]=fq;// printf("%d %d\n", u, bl[u] ); pos[u]=mx[u]=++id; int k=0; for ( int i=head[u]; i; i=e[i].nxt ) if( sz[k]<sz[e[i].to] && e[i].to!=fat[u] ) k=e[i].to; if( k ){ dfs2(k, u, fq); mx[u]=max(mx[u], mx[k]); } for ( int i=head[u]; i; i=e[i].nxt ){ int v=e[i].to; if( v==fa || v==k ) continue; dfs2(v, u, v); mx[u]=max(mx[u], mx[v]); }}struct Node{ int flg; LL sum, add;}tr[N<<2];#define ls nd<<1#define rs nd<<1|1void pushdown(int nd, int l, int r){ if( tr[nd].flg ){ tr[nd].flg=0; tr[ls].flg=tr[rs].flg=1; tr[ls].add+=(LL)tr[nd].add, tr[rs].add+=(LL)tr[nd].add; int mid=(l+r)>>1; tr[ls].sum+=(LL)(mid-l+1)*tr[nd].add; tr[rs].sum+=(LL)(r-mid)*tr[nd].add; tr[nd].add=0; return ; }}void pushup(int nd){ tr[nd].sum=tr[ls].sum+tr[rs].sum;}void modify(int nd, int l, int r, int L, int R, int val){ if( L<=l && r<=R ){ tr[nd].flg=1; tr[nd].add+=(LL)val; tr[nd].sum+=(LL)(r-l+1)*val; return; } pushdown(nd,l,r); int mid=(l+r)>>1; if( mid>=L ) modify(ls,l,mid,L,R,val); if( mid<R ) modify(rs,mid+1,r,L,R,val); pushup(nd);}LL query(int nd, int l, int r, int L, int R){ if( L<=l && r<= R ){ return tr[nd].sum; } pushdown(nd,l,r); int mid=(l+r)>>1; LL ret=0; if ( mid>=L ) ret+=query(ls,l,mid,L,R); if ( mid<R ) ret+=query(rs,mid+1,r,L,R); return ret; }LL query(int nd){ LL ret=0; while( bl[nd]!=1 ){ ret+=query(1,1,n,pos[bl[nd]],pos[nd]); nd=fat[bl[nd]]; } ret+=query(1,1,n,1,pos[nd]); return ret;}/*inline int read(){ int f=1, x=0; char ch=getchar(); while( !isdigit(ch) ) { if(ch=='-')f=-1; ch=getchar(); } while( isdigit(ch) ) { x=x*10+ch-'0'; ch=getchar(); } return x*f; }*/int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f;}int main(){ n=read(), m=read(); for ( int i=1; i<=n; i++ ) v[i]=read(); for ( int i=1; i<n; i++ ){ int x, y; x=read(), y=read(); addeage(x,y), addeage(y,x); } dfs1(1,0); dfs2(1,0,1);// for ( int i=1; i<=n; i++ ) printf("%d ", pos[i] );// cout<<"\n"; // for ( int i=1; i<=n; i++ ) printf("%d ", mx[i] ); //--------------------------------------------------------------------------- for ( int i=1; i<=n; i++ ) modify(1,1,n,pos[i],pos[i],v[i]); while( m-- ){ int opt, x, y; opt=read(); if( opt==3 ) x=read(), printf("%lld\n", query(x) ); else if( opt==1 ) x=read(), y=read(), modify(1,1,n,pos[x],pos[x],y); else x=read(), y=read(), modify(1,1,n,pos[x],mx[x],y); }}
阅读全文
0 0
- bzoj4034 [HAOI2015]树上操作
- 【bzoj4034】[HAOI2015]树上操作
- BZOJ4034: [HAOI2015]树上操作
- [bzoj4034][HAOI2015]树上操作
- bzoj4034: [HAOI2015]树上操作
- 【BZOJ4034】【HAOI2015】树上操作
- bzoj4034 [HAOI2015]树上操作
- bzoj4034: [HAOI2015]树上操作
- BZOJ4034 [HAOI2015]树上操作
- 【bzoj4034】【HAOI2015】【树上操作】【树链剖分】
- 【HAOI2015】【BZOJ4034】树上操作T2
- bzoj4034 cogs1963 [HAOI2015]树上操作
- [题解]bzoj4034 HAOI2015 树上操作
- bzoj4034 [HAOI2015]树上操作(树链剖分)
- 【树链剖分】bzoj4034: [HAOI2015]树上操作
- BZOJ4034——[HAOI2015]树上操作
- 【BZOJ4034】树上操作(HAOI2015)-树链剖分
- BZOJ4034: [HAOI2015]树上操作(洛谷P3178)
- 判断自己的网络是不是公网IP
- C++内存处理
- JSTL标签
- 初接触SSM(Spring+Spring MVC+Mybatis)
- Java中的设计模式
- [bzoj4034][HAOI2015]树上操作
- 平面射影几何——齐次坐标
- OkHttp下载文件并带进度条
- 说说java NIO的一些个人总结
- webpack中的babel-loader
- Lua笔记--number的存储
- Linux 0.11
- 极限编程的最佳实践
- Java NIO使用及原理分析 (四)