【bzoj4034】树上操作 树链剖分+线段树
2017-02-13 10:50
330 查看
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=4034
【题解】
用树剖来做的话,做法很显然,比模板题还简单。
不过,据说可以用dfs序搞一搞。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
#define FILE "read"
#define MAXN 100010
#define up(i,j,n) for(ll i=j;i<=n;++i)
#define dn(i,j,n) for(ll i=j;i>=n;--i)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
namespace INIT{
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline ll read(){
ll x=0,f=1; char ch=getc();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();}
return x*f;
}
}using namespace INIT;
struct node{ll y,next;}e[MAXN*2];
ll n,m,len,z,a[MAXN],Link[MAXN],size[MAXN],f[MAXN],w[MAXN],deep[MAXN],son[MAXN],top[MAXN],tr[MAXN*8],delta[MAXN*8];
void insert(ll x,ll y){e[++len].next=Link[x];Link[x]=len;e[len].y=y;}
void dfs(ll x){
size[x]=1; son[x]=0;
for(ll i=Link[x];i;i=e[i].next){
if(e[i].y==f[x]) continue;
f[e[i].y]=x; deep[e[i].y]=deep[x]+1;
dfs(e[i].y); size[x]+=size[e[i].y];
if(size[e[i].y]>size[son[x]]) son[x]=e[i].y;
}
}
void dfs(ll x,ll temp){
w[x]=++z; top[x]=temp;
if(son[x]) dfs(son[x],temp);
for(ll i=Link[x];i;i=e[i].next)
if(e[i].y!=f[x]&&e[i].y!=son[x]) dfs(e[i].y,e[i].y);
}
void pushdown(ll x,ll l,ll r){
ll delt=delta[x],mid=(l+r)>>1;
tr[x<<1]+=delt*(mid-l+1); tr[x<<1|1]+=delt*(r-mid);
delta[x<<1]+=delt; delta[x<<1|1]+=delt;
delta[x]=0;
}
void add(ll p,ll l,ll r,ll x,ll y,ll v){
pushdown(p,l,r);
if(x>r||y<l) return;
if(x<=l&&y>=r) {tr[p]+=v*(r-l+1); delta[p]+=v; return;}
ll mid=(l+r)>>1;
add(p<<1,l,mid,x,y,v); add(p<<1|1,mid+1,r,x,y,v);
tr[p]=tr[p<<1]+tr[p<<1|1];
}
ll find(ll p,ll l,ll r,ll x,ll y){
pushdown(p,l,r);
if(x>r||y<l) return 0;
if(x<=l&&y>=r) return tr[p];
ll mid=(l+r)>>1;
return find(p<<1,l,mid,x,y)+find(p<<1|1,mid+1,r,x,y);
}
ll solve(ll x){
ll ans=0;
while(x){
ans+=find(1,1,z,w[top[x]],w[x]);
x=f[top[x]];
}
return ans;
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(); m=read();
up(i,1,n) a[i]=read();
up(i,1,n-1) {ll x=read(),y=read(); insert(x,y); insert(y,x);}
dfs(1); dfs(1,1);
up(i,1,n) add(1,1,z,w[i],w[i],a[i]);
up(i,1,m){
ll opt=read();
if(opt==1) {ll x=read(),v=read(); add(1,1,z,w[x],w[x],v);}
else if(opt==2) {ll x=read(),v=read(); add(1,1,z,w[x],w[x]+size[x]-1,v);}
else {ll x=read(); printf("%lld\n",solve(x));}
}
return 0;
}
【题解】
用树剖来做的话,做法很显然,比模板题还简单。
不过,据说可以用dfs序搞一搞。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
#define FILE "read"
#define MAXN 100010
#define up(i,j,n) for(ll i=j;i<=n;++i)
#define dn(i,j,n) for(ll i=j;i>=n;--i)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
namespace INIT{
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline ll read(){
ll x=0,f=1; char ch=getc();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();}
return x*f;
}
}using namespace INIT;
struct node{ll y,next;}e[MAXN*2];
ll n,m,len,z,a[MAXN],Link[MAXN],size[MAXN],f[MAXN],w[MAXN],deep[MAXN],son[MAXN],top[MAXN],tr[MAXN*8],delta[MAXN*8];
void insert(ll x,ll y){e[++len].next=Link[x];Link[x]=len;e[len].y=y;}
void dfs(ll x){
size[x]=1; son[x]=0;
for(ll i=Link[x];i;i=e[i].next){
if(e[i].y==f[x]) continue;
f[e[i].y]=x; deep[e[i].y]=deep[x]+1;
dfs(e[i].y); size[x]+=size[e[i].y];
if(size[e[i].y]>size[son[x]]) son[x]=e[i].y;
}
}
void dfs(ll x,ll temp){
w[x]=++z; top[x]=temp;
if(son[x]) dfs(son[x],temp);
for(ll i=Link[x];i;i=e[i].next)
if(e[i].y!=f[x]&&e[i].y!=son[x]) dfs(e[i].y,e[i].y);
}
void pushdown(ll x,ll l,ll r){
ll delt=delta[x],mid=(l+r)>>1;
tr[x<<1]+=delt*(mid-l+1); tr[x<<1|1]+=delt*(r-mid);
delta[x<<1]+=delt; delta[x<<1|1]+=delt;
delta[x]=0;
}
void add(ll p,ll l,ll r,ll x,ll y,ll v){
pushdown(p,l,r);
if(x>r||y<l) return;
if(x<=l&&y>=r) {tr[p]+=v*(r-l+1); delta[p]+=v; return;}
ll mid=(l+r)>>1;
add(p<<1,l,mid,x,y,v); add(p<<1|1,mid+1,r,x,y,v);
tr[p]=tr[p<<1]+tr[p<<1|1];
}
ll find(ll p,ll l,ll r,ll x,ll y){
pushdown(p,l,r);
if(x>r||y<l) return 0;
if(x<=l&&y>=r) return tr[p];
ll mid=(l+r)>>1;
return find(p<<1,l,mid,x,y)+find(p<<1|1,mid+1,r,x,y);
}
ll solve(ll x){
ll ans=0;
while(x){
ans+=find(1,1,z,w[top[x]],w[x]);
x=f[top[x]];
}
return ans;
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(); m=read();
up(i,1,n) a[i]=read();
up(i,1,n-1) {ll x=read(),y=read(); insert(x,y); insert(y,x);}
dfs(1); dfs(1,1);
up(i,1,n) add(1,1,z,w[i],w[i],a[i]);
up(i,1,m){
ll opt=read();
if(opt==1) {ll x=read(),v=read(); add(1,1,z,w[x],w[x],v);}
else if(opt==2) {ll x=read(),v=read(); add(1,1,z,w[x],w[x]+size[x]-1,v);}
else {ll x=read(); printf("%lld\n",solve(x));}
}
return 0;
}
相关文章推荐
- BZOJ 4034 树上操作 (树链剖分 线段树)
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
- BZOJ - 4034 树上操作 (Dfs序列 + 线段树) || (树链剖分 + 线段树)|| (树状数组)
- 【树链剖分(DFS序)+线段树】BZOJ4034(HAOI2015)[树上操作]题解
- |BZOJ 4034|树链剖分|线段树|[HAOI2015]树上操作
- BZOJ[4034][HAOI2015]树上操作 树链剖分+线段树
- BZOJ 4034 树上操作(树链剖分 + 线段树)
- bzoj 4034: [HAOI2015]树上操作(树链剖分+线段树区间更新)
- |BZOJ 4034|树链剖分|线段树|[HAOI2015]树上操作
- BZOJ-4034: [HAOI2015]树上操作 (树链剖分 入门题 子树整体修改 线段树 区间修改+查询)
- bzoj4034 [HAOI2015]树上操作(树链剖分)
- 【bzoj 4034】树上操作(树链剖分)
- bzoj 4034: [HAOI2015]树上操作——树链剖分
- 【BZOJ4034】【HAOI2015】树上操作(树链剖分)
- bzoj 4034: [HAOI2015]树上操作 树链剖分
- bzoj 4034: 树上操作 线段树
- BZOJ 4034: [HAOI2015]树上操作【树链剖分】【DFS序】
- [BZOJ 4034][HAOI 2015] 树上操作 树链剖分+DFS序
- 【bzoj4034】【HAOI2015】【树上操作】【树链剖分】
- bzoj 4034: [HAOI2015]树上操作 (树链剖分)