hdu 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(树链剖分+线段树区间更新)的更多相关文章
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并
题目描述 给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走.m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开 ...
- Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组
Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...
- 【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) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- 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 ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
随机推荐
- SqlDataAdapter简单介绍 (转)
From: http://blog.sobnb.com/u/92/5532.html 一.特点介绍 1.表示用于填充 DataSet 和更新 SQL Server 数据库的一组数据命令和一个数据库连 ...
- first time to use github
first time to use github and feeling good. 学习软件工程,老师要求我们用这个软件管理自己的代码,网站是全英的,软件也简单易用,方便 https://githu ...
- [转帖]从 2G 到 5G,手机上网话语权的三次改变
从 2G 到 5G,手机上网话语权的三次改变 美国第一大电信运营商 Verizon 公司的 CEO Hans Vestberg 手持一部 iPad,屏幕上显示俯瞰地面的飞行地图.400 多公里外的洛杉 ...
- Oracle12c Clone PDB 的方法
1. 创建PDB的存放路径,举例: 2. 设置 数据库创建数据文件的目录 alter system set db_Create_file_dest='C:\app\Administrator\orad ...
- SAP入行就业
就大局势来说, 缺乏人最多的模块有abap 还有就是FICO 和MM. 如果您 英语水平特别高的话,建议您学习FICO HR 或BW. 如果您想追求高薪,那就是FICO无疑了.想快速就业或者有编程基础 ...
- js輸出
js訪問html的某個元素,使用document.getElementByID(); document.write()僅僅向文檔輸出內容,如果在頁面已經加載后輸出,原來頁面的內容會被覆蓋. docum ...
- html 框架 內聯框架
框架的作用:可以在瀏覽器同時顯示不止一個html頁面.一個html文檔也叫做一個框架. 垂直框架:設置窗口垂直排列顯示成一行 <frameset cols="20%,80%" ...
- LODOP打印控件关联输出各内容
Lodop打印控件利用SET_PRINT_STYLEA里面的“LinkedItem”可以把多个独立的内容关联起来,让它们顺序打印.这样,就可以实现很多效果,例如一些内容紧跟着表格下方输出,关联表格后就 ...
- 一名网工对Linux运维的一次经历
我是一名名副其实的网络工程师,驻场于某市数字化城乡管理指挥中心(简称数字城管),主要针对中大型网络系统,路由.交换机.存储.小型机等设备进行维护,主要工作职责主要分为两种: 对网络系统中的网络设备(路 ...
- 国产首款5G手机抢先亮相:如此给力的说!
5G网络是接下来移动互联网发展的主旋律,各家都在努力跟进,目前最积极的当属手机厂商,而2019年我们就能看到多款5G手机降临了. 在11月27日的未来信息通信技术国际研讨会上,vivo展示了他们正在研 ...