BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 14982 Solved: 6081
[Submit][Status][Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
1
2
2
10
6
5
6
5
16
——————————————题解
毕竟是模板……
所谓的线段树维护链,就是建很多个线段树,节点一个挨着一个省空间
代码量……真是……
//大家吼,我要砍树了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <string.h>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
#define inf 0x7fffffff
//#define ivorysi
#define mo 97797977
#define hash 974711
#define base 47
#define MAXN 30005
#define fi first
#define se second
#define pii pair<int,int>
using namespace std;
//树的存储
struct node {
int to,next;
}edge[MAXN*];
int head[MAXN],sumedge,n,q;
int val[MAXN];//点值 void add(int u,int v) {
edge[++sumedge].to=v;
edge[sumedge].next=head[u];
head[u]=sumedge;
}
//线段树部分变量定义
struct data {
int l,r,//边界
lson,//左儿子(因为不能直接位运算要节省空间)
rson,//右儿子(因为不能直接位运算要节省空间)
sum,//区间总和
maxp,//区间最大值
fa;//单点更新优化
data() {
l=,r=,lson=,rson=,sum=,maxp=-inf,fa=;
}
}tree[MAXN*];
int treecnt;//树点个数
int w[MAXN];//单点更新优化 //剖分部分变量定义
int fa[MAXN],//父亲
dep[MAXN],//深度
size[MAXN],//子树大小
son[MAXN],//重儿子
rank[MAXN],//在链中的位置
belong[MAXN],//属于哪条链
top[MAXN],//这个点所在链的深度最小的点
linkcnt,//链数
lroot[MAXN];//每条链的树根 //剖分部分
void dfs1(int u) {//size,fa,son,dep
size[u]=;
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].to;
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+;
dfs1(v);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
}
void build(int p,int l,int r);
vector<int> line;
void dfs2(int u) {//belong,top,rank
if(!belong[u]) {
belong[u]=++linkcnt;
top[linkcnt]=u;
rank[u]=; }
line.push_back(u);
if(!son[u]) {
lroot[belong[u]]=++treecnt;
build(treecnt,,line.size());
line.clear();
return;
}
belong[son[u]]=belong[u];
rank[son[u]]=rank[u]+;
dfs2(son[u]);
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].to;
if(v!=son[u] && v!=fa[u])
dfs2(v);
} }
//剖分部分结束
//————————————————————————————
//线段树部分
void build(int p,int l,int r) {
tree[p].l=l;
tree[p].r=r;
if(l==r) {
tree[p].sum=val[line[l-]];
tree[p].maxp=val[line[l-]];
w[line[l-]]=p;
return;
}
int mid=(l+r)>>;
tree[p].lson=++treecnt;
tree[treecnt].fa=p;
build(treecnt,l,mid);
int t1=tree[tree[p].lson].maxp;
int t3=tree[tree[p].lson].sum;
tree[p].rson=++treecnt;
tree[treecnt].fa=p;
build(treecnt,mid+,r);
int t2=tree[tree[p].rson].maxp;
int t4=tree[tree[p].rson].sum;
tree[p].sum+=t3+t4;
tree[p].maxp=max(t1,t2);
return;
}
void change(int u) {
tree[w[u]].sum=tree[w[u]].maxp=val[u];
int z=tree[w[u]].fa;
while(z!=) {
tree[z].sum=tree[tree[z].lson].sum+tree[tree[z].rson].sum;
tree[z].maxp=max(tree[tree[z].lson].maxp,tree[tree[z].rson].maxp);
z=tree[z].fa;
}
}
int treeqsum(int p,int l,int r) {
if(l <= tree[p].l && r >= tree[p].r) {
return tree[p].sum;
}
int mid=(tree[p].l+tree[p].r)>>;
int t1=,t2=;
if(l <= mid) {
t1=treeqsum(tree[p].lson,l,r);
}
if(r > mid){
t2=treeqsum(tree[p].rson,l,r);
}
return t1+t2;
}
int treeqmax(int p,int l,int r) {
if(l <= tree[p].l && r >= tree[p].r) {
return tree[p].maxp;
}
int mid=(tree[p].l+tree[p].r)>>;
int t1=-inf,t2=-inf;
if(l <= mid) {
t1=treeqmax(tree[p].lson,l,r);
}
if(r > mid){
t2=treeqmax(tree[p].rson,l,r);
}
return max(t1,t2);
}
//线段树部分结束
//——————————————————————————
//解决问题部分
int qsum(int u,int v){
int x=top[belong[u]],y=top[belong[v]],res=;
while(belong[u]!=belong[v]) {
if(dep[x]>dep[y]){
res+=treeqsum(lroot[belong[x]],tree[lroot[belong[x]]].l,rank[u]);
u=fa[x];
}
else {
res+=treeqsum(lroot[belong[y]],tree[lroot[belong[y]]].l,rank[v]);
v=fa[y];
}
x=top[belong[u]],y=top[belong[v]];
}
x=max(rank[u],rank[v]);
y=rank[u]+rank[v]-x;
res+=treeqsum(lroot[belong[u]],y,x);
return res; }
int qmax(int u,int v) {
int x=top[belong[u]],y=top[belong[v]],res=-inf;
while(belong[x]!=belong[y]) {
if(dep[x]>dep[y]){
res=max(res,treeqmax(lroot[belong[x]],tree[lroot[belong[x]]].l,rank[u]));
u=fa[x];
}
else {
res=max(res,treeqmax(lroot[belong[y]],tree[lroot[belong[y]]].l,rank[v]));
v=fa[y];
}
x=top[belong[u]],y=top[belong[v]];
}
x=max(rank[u],rank[v]);
y=rank[u]+rank[v]-x;
res=max(res,treeqmax(lroot[belong[u]],y,x));
return res;
}
void prepare() {
int u,v;
scanf("%d",&n);
xiaosiji(i,,n) {
scanf("%d %d",&u,&v);
add(u,v),add(v,u);
}
siji(i,,n) {
scanf("%d",&val[i]);
}
scanf("%d",&q);
dfs1(),dfs2();
}
void solve() {
prepare();
char ord[];
siji(i,,q) {
scanf("%s",ord);
if(ord[]=='C') {
int u;
scanf("%d",&u);
//之前写成scanf("%d%d",&u,&val[u]);应该是因为它获得的是原来的u,可能是个很大的野值
scanf("%d",&val[u]);
change(u);
}
else if(ord[]=='M') {
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n",qmax(u,v));
}
else {
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n",qsum(u,v));
}
}
}
int main(int argc, char const *argv[])
{
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
solve();
}
BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)的更多相关文章
- Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)
[ZJOI2008]树的统计Count ★★★ 输入文件:bzoj_1036.in 输出文件:bzoj_1036.out 简单对比 时间限制:5 s 内存限制:162 MB [题目描述] 一棵树上有n ...
- 【bzoj1036】[ZJOI2008]树的统计Count 树链剖分+线段树
题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v ...
- BZOJ 2243 染色 | 树链剖分模板题进阶版
BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...
- BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14302 Solved: 5779[Submit ...
- Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 11102 Solved: 4490[Submit ...
- BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )
树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...
- bzoj 1036: [ZJOI2008]树的统计Count 树链剖分+线段树
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 16294 Solved: 6645[Submit ...
- BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)
[ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14968 Solved: 6079[Submit][Stat ...
- BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时 ...
随机推荐
- 疯狂Android讲义
1 Android应用和开发环境2 Android应用的界面编程3 Android的事件处理4 Activity Fragment5 Intent IntentFilter6 Android应用的资源 ...
- iis配置访问错误
最近换工作,忙着熟悉新的环境,新的框架技术(银行用的EBF),各种碰坑. 总结一下iis配置过程当中遇到的一个坑------ 按照环境搭配手册一步一步的配置,在我机器上访问一直报500的错,但是同样的 ...
- Linux 下搭建 Svn+Apache
一.安装apache 1.检查apache是否安装 rpm -qa|grep httpd 2.使用yum安装apache yum -y install httpd 3.记住安装的版本号 httpd.x ...
- IOS艺术字及简单的图文混排
NSString* alertText = [NSString stringWithFormat:@" 以下%d节课程(总课酬¥%.02lf)家长们尚未结课并评价,请尽快联系家长,否则无法获 ...
- 动态规划:POJ 3616 Milking Time
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> ...
- SQL语句(十九)——存储过程(练习)
select * From Student select * From Course select * from SC --INSERT INTO SC (Sno, Cno, Grade) --VAL ...
- NGINX配置PHP解析
<?php phpinfo(); ?> location ~ \.php$ { root html; fastcgi_pass ; fastcgi_index index.php; fas ...
- Jenkins + jmeter + ant + git 自动化集成
背景: 目前测试组项目多,手头任务紧,且回归测试任务量较大,经过组内讨论采用相对快速高效的方式(自动化接口测试类型),在迭代任务中把主要精力集中在新需求测试:而回归测试时,主要采用自动化测试,提高测 ...
- django project 的快速构建
2003年,堪萨斯(Kansas)州 Lawrence 城中的一个 网络开发小组 ——World Online 小组,为了方便制作维护当地的几个新闻站点(一般要求几天或者几小时内被建立),Adrian ...
- 小记 百度地图 soso地图 经纬度偏移
项目里遇到了这么个问题,数据库原有数据是微信上用的,所以是soso地图坐标, 但是现在要做百度地图,坐标偏移严重,网上找了也没说偏移多少,自己手动测试10多分钟,得到个大概值,反正差不多就行了. so ...