HYSBZ 4034 【树链剖分】+【线段树 】
<题目链接>
题目大意:
Input
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
Sample Output
6
9
13
Hint
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
解题分析:
很明显本题用树链剖分解决,重点是解决第二个操作,以x为根的子树所有的节点权值都增加a。其实,在明白了树链剖分原理后,不难发现,以x为根的所有节点必然在线段树上是一段连续的区间,并且x在线段树上的编号为区间的左端点,下面我们就可以直接通过该节点的子节点数量找出以该节点为根的在线段树上编号最大的子节点,即该区间的右端点,找到了对应的区间,然后进行线段树的区间更新就行。
下面的代码WA了。。。先记录一下
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; #define ll long long
#define Lson l,mid,rt<<1
#define Rson mid+1,r,rt<<1|1
const int M =1e6+;
int n,m,cnt,tot,endloc;
int head[M],sz[M],son[M],dep[M],f[M],id[M],rnk[M],top[M];
int arr[M]; struct EDGE{
int to;
int next;
}edge[M<<];
struct Tree{
int lazy;
ll sum;
}tr[M<<];
void init(){
cnt=tot=;
memset(head,-,sizeof(head));
}
void Pushup(int rt){
tr[rt].sum=tr[rt<<].sum+tr[rt<<|].sum;
}
void Pushdown(int rt,int len){
if(tr[rt].lazy){
int tmp=tr[rt].lazy;
tr[rt].lazy=;
tr[rt<<].lazy+=tmp;
tr[rt<<|].lazy+=tmp;
tr[rt<<].sum+=tmp*(len-(len>>));
tr[rt<<|].sum+=tmp*(len>>);
}
}
void add(int u,int v){
edge[++cnt].to=v,edge[cnt].next=head[u];
head[u]=cnt;
} void dfs(int u,int fa,int d){
sz[u]=,f[u]=fa,dep[u]=d,son[u]=-;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==fa)continue;
dfs(v,u,d+);
sz[u]+=sz[v];
if(son[u]==-||sz[v]>sz[son[u]])son[u]=v;
}
} void dfs1(int u,int t){
id[u]=++tot;
rnk[tot]=u;
top[u]=t;
if(son[u]==-)return;
dfs1(son[u],t);
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==f[u]||v==son[u])continue;
dfs1(v,v);
}
} void dfsrot(int u,int fa){
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==fa)continue;
endloc=max(endloc,id[v]); //在以rot为根的所有子节点,在线段树上是一段连续的区间,所以只需要记录区间的右端点就行
dfsrot(v,u);
}
} void build(int l,int r,int rt){
tr[rt].lazy=;
if(l==r){
tr[rt].sum=arr[rnk[l]];
return;
}
int mid=(l+r)>>;
build(Lson);
build(Rson);
Pushup(rt);
} void update1(int loc,int val,int l,int r,int rt){ //单点更新
if(l==r){
tr[rt].sum+=val;
return;
}
Pushdown(rt,r-l+);
int mid=(l+r)>>;
if(loc<=mid)update1(loc,val,Lson);
if(loc>mid)update1(loc,val,Rson);
Pushup(rt);
} void update2(int L,int R,int val,int l,int r,int rt){ //线段树区间修改
if(L<=l&&r<=R){
tr[rt].lazy+=val;
tr[rt].sum+=val*(r-l+);
return;
}
Pushdown(rt,r-l+);
int mid=(l+r)>>;
if(L<=mid)
update2(L,R,val,Lson);
if(R>mid)
update2(L,R,val,Rson);
Pushup(rt);
} ll query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return tr[rt].sum;
}
Pushdown(rt,r-l+);
int mid=(l+r)>>;
ll ans=;
if(L<=mid)
ans+=query(L,R,Lson);
if(R>mid)
ans+=query(L,R,Rson);
return ans;
} void Query(int x){
ll ans=;
int fx=top[x];
while(fx!=){ //(因为1为整棵树的根)当x点不在以1为链首的重链上时
ans+=query(id[fx],id[x],,n,);
x=f[fx],fx=top[x];
}
ans+=query(id[],id[x],,n,);
printf("%lld\n",ans);
} int main(){
while(scanf("%d%d",&n,&m)!=EOF){
init();
for(int i=;i<=n;i++)scanf("%d",&arr[i]);
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
} dfs(,-,);
dfs1(,);
build(,n,);
while(m--){
int cal;scanf("%d",&cal);
if(cal==){
int loc,val;
scanf("%d%d",&loc,&val);
update1(id[loc],val,,n,);
}
else if(cal==){
int rot,val;
scanf("%d%d",&rot,&val);
int start=id[rot]; //根据树链剖分的原理,根节点就是该区间的左端点
update2(start,start+sz[rot]-,val,,n,);
}
else{
int loc;
scanf("%d",&loc);
Query(loc);
}
}
}
return ;
}
AC代码:转载于 >>>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 100005
#define lson l,mid,node<<1
#define rson mid+1,r,node<<1|1
using namespace std;
typedef long long ll;
ll sum[maxn*],col[maxn*];
int n,m,q;
int cot=,cnt;
int tid[maxn],top[maxn],tim;
int dep[maxn],fa[maxn],sz[maxn],Rank[maxn];
int first[maxn],son[maxn];
int End[maxn];
ll w[maxn]; struct Edge{
int v,nxt;
Edge(int _v=,int _nxt=){
v=_v,nxt=_nxt;
}
}e[maxn*]; void init(){
cot=;
tim=;
memset(first,-,sizeof(first));
memset(son,-,sizeof(son));
} void add(int u,int v){
cot++;
e[cot]=Edge(v,first[u]);
first[u]=cot;
cot++;
e[cot]=Edge(u,first[v]);
first[v]=cot;
} //树链剖分部分 void dfs1(int u,int father,int d){
dep[u]=d;
fa[u]=father;
sz[u]=;
for(int i=first[u];i!=-;i=e[i].nxt){
int v=e[i].v;
if(v!=father){
dfs1(v,u,d+);
sz[u]+=sz[v];
if(son[u]==-||sz[v]>sz[son[u]])
son[u]=v;
}
}
} void dfs2(int u,int tp){
top[u]=tp;
tid[u]=++tim;
Rank[tid[u]]=u;
if(son[u]!=-) dfs2(son[u],tp);
for(int i=first[u];i!=-;i=e[i].nxt){
int v=e[i].v;
if(v!=son[u]&&v!=fa[u]) dfs2(v,v);
}
End[u]=tim;
} //线段树部分
inline void pushup(int node){
sum[node]=sum[node<<]+sum[node<<|];
} inline void pushdown(int node,int l,int r){
int mid=(l+r)>>;
if(col[node]){
col[node<<]+=col[node];
col[node<<|]+=col[node];
sum[node<<]+=(mid-l+)*col[node];
sum[node<<|]+=(r-mid)*col[node];
col[node]=;
}
} void build(int l,int r,int node){
col[node]=;
if(l==r){
sum[node]=w[Rank[l]];
return;
}
int mid=(l+r)>>;
build(lson);
build(rson);
pushup(node);
} void update(int l,int r,int node,int L,int R,int val){
if(L<=l&&R>=r){
col[node]+=1LL*val;
sum[node]+=1LL*val*(r-l+);
return;
}
pushdown(node,l,r);
int mid=(l+r)>>;
//只要在范围内都要考虑
if(L<=mid) update(lson,L,R,val);
if(R>mid) update(rson,L,R,val);
pushup(node);
} ll query(int l,int r,int node,int L,int R){
if(l>=L&&r<=R) return sum[node];
pushdown(node,l,r);
int mid=(l+r)>>;
ll ret=;
if(L<=mid) ret+=query(lson,L,R);
if(R>mid) ret+=query(rson,L,R);
pushup(node);
return ret;
} ll getans(int x,int y){
ll ans=;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query(,n,,tid[top[x]],tid[x]);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=query(,n,,tid[x],tid[y]);
return ans;
} int main(){
int u,v;
int op;
int a,x;
while(~scanf("%d%d",&n,&m)) {
init();
for(int i=;i<=n;i++) scanf("%lld",&w[i]);
for(int i=;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
}
dfs1(,-,);
dfs2(,);
build(,n,); for(int i=;i<=m;i++){
scanf("%d",&op);
if(op==){
scanf("%d",&x);
ll ans=getans(,x);
printf("%lld\n",ans);
}
else{
scanf("%d%d",&x,&a);
update(,n,,tid[x],op==?tid[x]:End[x],a);
}
}
}
return ;
}
HYSBZ 4034 【树链剖分】+【线段树 】的更多相关文章
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
随机推荐
- NSLayoutConstraint 使用详解 VFL使用介绍
注意 使用前必须先取消所有的你想设置View 的 Autoresizing 属性 因为 Autoresizing Layout不能共存 系统默认是 Autoresizing for v in su ...
- 51 NOd 2006 飞行员配对(匈牙利算法二分匹配)
题目来源: 网络流24题 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一 ...
- 正则 ?<= 和 ?= 用法,范例
(exp) 匹配exp,并捕获文本到自动命名的组里(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)(?:exp) 匹配exp,不捕 ...
- 用C语言实现窗口抖动
#include "stdafx.h" #include <stdio.h> #include<Windows.h> int main() { ; //休眠 ...
- 升级到 Android Studio 3.0 + Gradle 4.1 遇到的一些坑及解决方案
问题一: Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated{apkD ...
- Oracle数据重复,只取一条
--方法一 select * from tb_supply where rowid=any(select max(rowid) from tb_supply group by phone_id) -- ...
- 关于k8s安装脚本方面的草稿
周六作的, 慢慢完善. #! /usr/bin/env bash set -e set -u set -x #让此脚本可以重复执行,所以加了一些判断 #使用系统的PATH环境 export PATH= ...
- 根据id查询所有子节点/父节点,mysql 以及ssm前后台处理流程
1.所示案例数据表结构设计如下所示: 2.案例数据如下所示: 3.mysql查询语句可以查询出父级目录信息: 注意:自己的数据表表名称,切记手动修改,字段名称(特别注意id,parent_id字段名称 ...
- Javascript面向对象编程:非构造函数的继承
今天是最后一个部分,介绍不使用构造函数实现"继承". 一.什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人". var Ch ...
- Jmeter入门(压力测试)
Jmeter介绍 Jmeter是一款使用Java开发的,开源免费的,测试工具, 主要用来做功能测试和性能测试(压力测试/负载测试). 而且用Jmeter 来测试 Restful API, 非常好用. ...