传送门:Problem 3966

https://www.cnblogs.com/violet-acmer/p/9711441.html

学习资料:

  [1]线段树区间更新:https://blog.csdn.net/zhhe0101/article/details/53871453

           https://yq.aliyun.com/articles/252586

  [2]树链剖分:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html

         https://wenku.baidu.com/view/7548d8706ad97f192279168884868762caaebbfc.html?from=search

题意:

  敌军有N个营地,这N个营地通过M条边连接;
  每个营地有且仅有一条边连接(意味着M=N-1,就是一颗含有N个节点的树)
  要求支持两种操作:
  1营地u与营地v以及其之间的所有营地增加或减少ai个士兵。
  2询问营地u当前含有的士兵个数

题解:

  树链剖分模板题。

  实质上树链剖分进行了点对点的一次映射,保证了重链上的点在线段树上的位置是连续的。

  树链剖分的两个性质(转):

    性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v];

    性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。

  保证了一个区间的时间复杂度是log2(n)。

  要分清3种标号含义(易混) :树中节点标号,树中节点对应线段树中位置标号,线段树中区间标号。

树链剖分相关数组意义 :

  siz[i] : 以i为根的子树的大小

  fa[i] : i节点的父亲

  depth[i]  : i节点的深度

  son[i] : i节点的重儿子(所有儿子中size最大的)

  tid[i] : i节点在线段树中对应的位置    

  top[i] : i节点所在重链的顶端节点,若为轻链,则为自身。

  rid[i] : 线段树中所对应树中节点(作用和tid[ ] 正好相反)。

AC代码:

  摘抄自大佬博客:

  分析:典型的树链剖分题目,先进行剖分,然后用线段树去维护即可,注意HDU的OJ采用Windows系统,容易爆栈,所以在代码前面加上:

  #pragma comment(linker, "/STACK:1024000000,1024000000")进行手动扩栈。

  (但不加也可以AC)

 //#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ls(x)((x)<<1)
#define rs(x)((x)<<1 | 1)
const int maxn=5e4+; int A[maxn];
//========链式前向星========
struct Node1
{
int to;
int next;
}edge[maxn<<];
int head[maxn];
int cnt;
void addEdge(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
//==========================
//=========树链剖分=========
int fa[maxn];
int son[maxn];
int tid[maxn];
int rid[maxn];
int siz[maxn];
int top[maxn];
int depth[maxn];
int label; void dfs1(int u,int f,int d)
{
fa[u]=f;
siz[u]=;
depth[u]=d;
for(int i=head[u];~i;i=edge[i].next)
{
int to=edge[i].to;
if(to != f)
{
dfs1(to,u,d+);
siz[u] += siz[to];
if(son[u] == - || siz[to] > siz[son[u]])
son[u]=to;
}
}
}
void dfs2(int u,int newTop)
{
top[u]=newTop;
tid[u]=++label;
rid[tid[u]]=u;
if(son[u] == -)
return ;
dfs2(son[u],newTop);
for(int i=head[u];~i;i=edge[i].next)
{
int to=edge[i].to;
if(to != son[u] && to != fa[u])
dfs2(to,to);
}
}
//==========================
//==========线段树==========
struct Node2
{
int l,r;
int val;
int lazy;
int mid(){
return l+((r-l)>>);
}
}segTree[maxn<<];
void buildTree(int l,int r,int pos)
{
segTree[pos].l=l,segTree[pos].r=r;
segTree[pos].lazy=;
if(l == r)
{
segTree[pos].val=A[rid[l]];
return ;
}
int mid=l+((r-l)>>);
buildTree(l,mid,ls(pos));
buildTree(mid+,r,rs(pos));
}
void pushDown(int pos)
{ if(segTree[pos].lazy != )
{
segTree[ls(pos)].lazy += segTree[pos].lazy;
segTree[rs(pos)].lazy += segTree[pos].lazy; //segTree[ls(pos)].val += segTree[pos].lazy;
//segTree[rs(pos)].val += segTree[pos].lazy; segTree[pos].lazy=;
}
}
void update(int a,int b,int val,int pos)
{
if(a <= segTree[pos].l && b >= segTree[pos].r)
{
segTree[pos].lazy += val;
//segTree[pos].val += val;
return ;
}
pushDown(pos); int mid=segTree[pos].mid();
if(b <= mid)
update(a,b,val,ls(pos));
else if(a > mid)
update(a,b,val,rs(pos));
else
{
update(a,mid,val,ls(pos));
update(mid+,b,val,rs(pos));
}
}
int query(int k,int pos)
{
if(segTree[pos].l == segTree[pos].r)
return segTree[pos].val+segTree[pos].lazy; pushDown(pos);
int mid=segTree[pos].mid(); if(k <= mid)
return query(k,ls(pos));
else
return query(k,rs(pos));
}
//==========================
void Find(int a,int b,int val)
{
while(top[a] != top[b])
{
if(depth[top[a]] > depth[top[b]])
{
update(tid[top[a]],tid[a],val,);
a=fa[top[a]];
}
else
{
update(tid[top[b]],tid[b],val,);
b=fa[top[b]];
}
}
if(tid[a] > tid[b])
swap(a,b);
update(tid[a],tid[b],val,);
} void init()
{
cnt=;
memset(head,-,sizeof(head));
label=;
memset(son,-,sizeof(son));
}
int main()
{
int n,m,q;
while(~scanf("%d%d%d",&n,&m,&q))
{
init();
for(int i=;i <= n;++i)
scanf("%d",A+i);
for(int i=;i <= m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
dfs1(,,);
dfs2(,);
buildTree(,label,);
char op[];
for(int i=;i <= q;++i)
{
scanf("%s",op);
if(op[] == 'Q')
{
int c;
scanf("%d",&c);
printf("%d\n",query(tid[c],));
}
else
{
int c1,c2,k;
scanf("%d%d%d",&c1,&c2,&k);
if(op[] == 'D')
k = -k;
Find(c1,c2,k);
}
}
}
return ;
}

分割线:2019.5.10

省赛倒计时2天;

重新温习了一下树链剖分,改了改代码风格:

 #pragma comment(linker,"/STACK:1024000000,1024000000")///手动扩栈
#include<bits/stdc++.h>
using namespace std;
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=5e4+; int n,m,q;///n个点 ,m条边(m=n-1),q次询问
int a[maxn];///a[i]:初始i营地有a[i]个士兵
int num;
int head[maxn];
struct Edge
{
int to;
int next;
}G[maxn<<];
void addEdge(int u,int v)
{
G[num]=Edge{v,head[u]};
head[u]=num++;
}
int fa[maxn];
int tid[maxn];
int rid[maxn];
int siz[maxn];
int son[maxn];
int top[maxn];
int dep[maxn];
struct Seg
{
int l,r;
int val;
int lazy;
int mid(){return l+((r-l)>>);}
int len(){return r-l+;};
}seg[maxn<<]; void pushDown(int pos)
{
int &lazy=seg[pos].lazy;
if(lazy)
{
seg[ls(pos)].lazy += lazy;
seg[rs(pos)].lazy += lazy;
}
lazy=;
}
void buildSegTree(int l,int r,int pos)
{
seg[pos].l=l;
seg[pos].r=r;
seg[pos].lazy=;
seg[pos].val=;
if(l == r)
{
seg[pos].val=a[rid[l]];///l点在树中对应的编号rid[l]
return ;
}
int mid=l+((r-l)>>);
buildSegTree(l,mid,ls(pos));
buildSegTree(mid+,r,rs(pos));
}
int Query(int l,int pos)
{
if(seg[pos].l == seg[pos].r)
return seg[pos].val+seg[pos].lazy; pushDown(pos); int mid=seg[pos].mid();
if(l <= mid)
return Query(l,ls(pos));
else
return Query(l,rs(pos));
}
void Update(int l,int r,int pos,int val)
{
if(seg[pos].l == l && seg[pos].r == r)
{
seg[pos].lazy += val;
return ;
}
pushDown(pos); int mid=seg[pos].mid();
if(r <= mid)
Update(l,r,ls(pos),val);
else if(l > mid)
Update(l,r,rs(pos),val);
else
{
Update(l,mid,ls(pos),val);
Update(mid+,r,rs(pos),val);
}
}
void Find(int u,int v,int val)
{
while(top[u] != top[v])///u,v不在同一条重链上
{
if(dep[top[u]] > dep[top[v]])
swap(u,v); Update(tid[top[v]],tid[v],,val);///让u,v一步一步靠到同一条重链上
v=fa[top[v]];
}
///return 语句根据题意而定
///再此题中,u==v时就是单点更新
// if(u == v)
// return ;
if(dep[u] > dep[v])
swap(u,v);
///这次不是tid[son[u]],因为上次是边权存在了儿子节点里
Update(tid[u],tid[v],,val);
}
void DFS1(int u,int f,int depth)
{
fa[u]=f;
siz[u]=;
dep[u]=depth;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(v == f)
continue; DFS1(v,u,depth+); siz[u] += siz[v];
if(son[u] == - || siz[v] > siz[son[u]])
son[u]=v;
}
}
void DFS2(int u,int anc,int &k)
{
tid[u]=++k;
rid[k]=u;
top[u]=anc;
if(son[u] == -)
return ;
DFS2(son[u],anc,k); for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(v != fa[u] && v != son[u])
DFS2(v,v,k);
}
}
void Solve()
{
DFS1(,,);
int k=;
DFS2(,,k);
buildSegTree(,k,); char order[];
while(q--)
{
scanf("%s",order);
if(order[] == 'Q')
{
int u;
scanf("%d",&u);
printf("%d\n",Query(tid[u],));///单点查询,查询u营地当前的人数
}
else
{
int u,v,val;
scanf("%d%d%d",&u,&v,&val);///区间更新,更新营地[u,v]人数 +val
if(order[] == 'D')
val=-val;///人数减少
Find(u,v,val);
}
}
}
void Init()
{
num=;
mem(head,-);
mem(son,-);
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&q))
{
Init();
for(int i=;i <= n;++i)
scanf("%d",a+i);
for(int i=;i <= m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
Solve();
}
return ;
}

hdu 3966(树链剖分+线段树区间更新)的更多相关文章

  1. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  2. POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )

    POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...

  3. 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并

    题目描述 给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走.m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开 ...

  4. Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组

    Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...

  5. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  6. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  7. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  8. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  9. 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 ...

  10. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

随机推荐

  1. M2事后会议报告

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? Beta阶段的爬虫需要更稳定.更高效.操作更便捷.在定义中爬取对性能和功能的要求高,典型用户和场景 ...

  2. 大三上学期安卓一边学一边开始做一个自己觉得可以的项目 广商小助手App 加油

    这项目构思好多 一个人一步一步来 一边做一边为后面应用铺设 广商小助手APP 设计出的软件登录场景 实现(算是可以) 界面大体出来了 界面点击方面也做了很多特效 上图其实点击各颜色后会出现各种图和反应 ...

  3. Maven相关问题解决.docx

    1. 问题 2. 原因 出现.lastUpdated结尾的文件的原因:由于网络原因没有将Maven的依赖下载完整,导致. 解决方案: 1.删除所有以.lastUpdate结尾的文件 a)1.切换到ma ...

  4. MSTSC 3389 端口修改

    1. 启动注册表编辑器. 2. 找到并单击以下注册表子项: 3. HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server ...

  5. dotnet core的下载地址 以及sdk和runtime的 version 简单说明

    1. dotnet core 2.1 的下载地址 https://dotnet.microsoft.com/download/dotnet-core/2.1 2. dotnet core 2.2 的下 ...

  6. python 安装influxdb-python

    一.Linux下安装 1.yum install -y git 2.安装pip,参考:https://app.yinxiang.com/shard/s41/sh/0338ba85-5443-453f- ...

  7. python数据统计量分析

    #-*- coding: utf-8 -*- #餐饮销量数据统计量分析 from __future__ import print_function import pandas as pd cateri ...

  8. python自动化运维笔记1 —— 系统性能信息模块psutil

    一.系统基础信息模块 1.1 系统性能信息模块psutil psutil是一个跨平台库(http://code.google.com/p/psutil/),能够轻松实现获取系统运行的进程和系统利用率( ...

  9. docker--命令详解

    查看版本: docker --version 查看docker信息: docker info 进入容器: docker exec -it bb /bin/bash #在容器中执行一个bash可以操作容 ...

  10. echarts之简单的入门——【一】做个带时间轴的柱状统计图

    百度Echarts 官网首页  http://echarts.baidu.com/ 配置项手册 http://echarts.baidu.com/option.html#title GL配置项手册 h ...