传送门: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)

  1 //#pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 using namespace std;
  6 #define ls(x)((x)<<1)
  7 #define rs(x)((x)<<1 | 1)
  8 const int maxn=5e4+10;
  9
 10 int A[maxn];
 11 //========链式前向星========
 12 struct Node1
 13 {
 14     int to;
 15     int next;
 16 }edge[maxn<<1];
 17 int head[maxn];
 18 int cnt;
 19 void addEdge(int u,int v)
 20 {
 21     edge[cnt].to=v;
 22     edge[cnt].next=head[u];
 23     head[u]=cnt++;
 24 }
 25 //==========================
 26 //=========树链剖分=========
 27 int fa[maxn];
 28 int son[maxn];
 29 int tid[maxn];
 30 int rid[maxn];
 31 int siz[maxn];
 32 int top[maxn];
 33 int depth[maxn];
 34 int label;
 35
 36 void dfs1(int u,int f,int d)
 37 {
 38     fa[u]=f;
 39     siz[u]=1;
 40     depth[u]=d;
 41     for(int i=head[u];~i;i=edge[i].next)
 42     {
 43         int to=edge[i].to;
 44         if(to != f)
 45         {
 46             dfs1(to,u,d+1);
 47             siz[u] += siz[to];
 48             if(son[u] == -1 || siz[to] > siz[son[u]])
 49                 son[u]=to;
 50         }
 51     }
 52 }
 53 void dfs2(int u,int newTop)
 54 {
 55     top[u]=newTop;
 56     tid[u]=++label;
 57     rid[tid[u]]=u;
 58     if(son[u] == -1)
 59         return ;
 60     dfs2(son[u],newTop);
 61     for(int i=head[u];~i;i=edge[i].next)
 62     {
 63         int to=edge[i].to;
 64         if(to != son[u] && to != fa[u])
 65             dfs2(to,to);
 66     }
 67 }
 68 //==========================
 69 //==========线段树==========
 70 struct Node2
 71 {
 72     int l,r;
 73     int val;
 74     int lazy;
 75     int mid(){
 76         return l+((r-l)>>1);
 77     }
 78 }segTree[maxn<<2];
 79 void buildTree(int l,int r,int pos)
 80 {
 81     segTree[pos].l=l,segTree[pos].r=r;
 82     segTree[pos].lazy=0;
 83     if(l == r)
 84     {
 85         segTree[pos].val=A[rid[l]];
 86         return ;
 87     }
 88     int mid=l+((r-l)>>1);
 89     buildTree(l,mid,ls(pos));
 90     buildTree(mid+1,r,rs(pos));
 91 }
 92 void pushDown(int pos)
 93 {
 94
 95     if(segTree[pos].lazy != 0)
 96     {
 97         segTree[ls(pos)].lazy += segTree[pos].lazy;
 98         segTree[rs(pos)].lazy += segTree[pos].lazy;
 99
100         //segTree[ls(pos)].val += segTree[pos].lazy;
101         //segTree[rs(pos)].val += segTree[pos].lazy;
102
103         segTree[pos].lazy=0;
104     }
105 }
106 void update(int a,int b,int val,int pos)
107 {
108     if(a <= segTree[pos].l && b >= segTree[pos].r)
109     {
110         segTree[pos].lazy += val;
111         //segTree[pos].val += val;
112         return ;
113     }
114     pushDown(pos);
115
116     int mid=segTree[pos].mid();
117     if(b <= mid)
118         update(a,b,val,ls(pos));
119     else if(a > mid)
120         update(a,b,val,rs(pos));
121     else
122     {
123         update(a,mid,val,ls(pos));
124         update(mid+1,b,val,rs(pos));
125     }
126 }
127 int query(int k,int pos)
128 {
129     if(segTree[pos].l == segTree[pos].r)
130         return segTree[pos].val+segTree[pos].lazy;
131
132     pushDown(pos);
133     int mid=segTree[pos].mid();
134
135     if(k <= mid)
136         return query(k,ls(pos));
137     else
138         return query(k,rs(pos));
139 }
140 //==========================
141 void Find(int a,int b,int val)
142 {
143     while(top[a] != top[b])
144     {
145         if(depth[top[a]] > depth[top[b]])
146         {
147             update(tid[top[a]],tid[a],val,1);
148             a=fa[top[a]];
149         }
150         else
151         {
152             update(tid[top[b]],tid[b],val,1);
153             b=fa[top[b]];
154         }
155     }
156     if(tid[a] > tid[b])
157         swap(a,b);
158     update(tid[a],tid[b],val,1);
159 }
160
161 void init()
162 {
163     cnt=0;
164     memset(head,-1,sizeof(head));
165     label=0;
166     memset(son,-1,sizeof(son));
167 }
168 int main()
169 {
170     int n,m,q;
171     while(~scanf("%d%d%d",&n,&m,&q))
172     {
173         init();
174         for(int i=1;i <= n;++i)
175             scanf("%d",A+i);
176         for(int i=1;i <= m;++i)
177         {
178             int u,v;
179             scanf("%d%d",&u,&v);
180             addEdge(u,v);
181             addEdge(v,u);
182         }
183         dfs1(1,1,0);
184         dfs2(1,1);
185         buildTree(1,label,1);
186         char op[3];
187         for(int i=1;i <= q;++i)
188         {
189             scanf("%s",op);
190             if(op[0] == 'Q')
191             {
192                 int c;
193                 scanf("%d",&c);
194                 printf("%d\n",query(tid[c],1));
195             }
196             else
197             {
198                 int c1,c2,k;
199                 scanf("%d%d%d",&c1,&c2,&k);
200                 if(op[0] == 'D')
201                     k = -k;
202                 Find(c1,c2,k);
203             }
204         }
205     }
206     return 0;
207 }

View Code


分割线:2019.5.10

省赛倒计时2天;

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

  1 #pragma comment(linker,"/STACK:1024000000,1024000000")///手动扩栈
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 #define ls(x) (x<<1)
  5 #define rs(x) (x<<1|1)
  6 #define mem(a,b) memset(a,b,sizeof(a))
  7 const int maxn=5e4+50;
  8
  9 int n,m,q;///n个点 ,m条边(m=n-1),q次询问
 10 int a[maxn];///a[i]:初始i营地有a[i]个士兵
 11 int num;
 12 int head[maxn];
 13 struct Edge
 14 {
 15     int to;
 16     int next;
 17 }G[maxn<<1];
 18 void addEdge(int u,int v)
 19 {
 20     G[num]=Edge{v,head[u]};
 21     head[u]=num++;
 22 }
 23 int fa[maxn];
 24 int tid[maxn];
 25 int rid[maxn];
 26 int siz[maxn];
 27 int son[maxn];
 28 int top[maxn];
 29 int dep[maxn];
 30 struct Seg
 31 {
 32     int l,r;
 33     int val;
 34     int lazy;
 35     int mid(){return l+((r-l)>>1);}
 36     int len(){return r-l+1;};
 37 }seg[maxn<<2];
 38
 39 void pushDown(int pos)
 40 {
 41     int &lazy=seg[pos].lazy;
 42     if(lazy)
 43     {
 44         seg[ls(pos)].lazy += lazy;
 45         seg[rs(pos)].lazy += lazy;
 46     }
 47     lazy=0;
 48 }
 49 void buildSegTree(int l,int r,int pos)
 50 {
 51     seg[pos].l=l;
 52     seg[pos].r=r;
 53     seg[pos].lazy=0;
 54     seg[pos].val=0;
 55     if(l == r)
 56     {
 57         seg[pos].val=a[rid[l]];///l点在树中对应的编号rid[l]
 58         return ;
 59     }
 60     int mid=l+((r-l)>>1);
 61     buildSegTree(l,mid,ls(pos));
 62     buildSegTree(mid+1,r,rs(pos));
 63 }
 64 int Query(int l,int pos)
 65 {
 66     if(seg[pos].l == seg[pos].r)
 67         return seg[pos].val+seg[pos].lazy;
 68
 69     pushDown(pos);
 70
 71     int mid=seg[pos].mid();
 72     if(l <= mid)
 73         return Query(l,ls(pos));
 74     else
 75         return Query(l,rs(pos));
 76 }
 77 void Update(int l,int r,int pos,int val)
 78 {
 79     if(seg[pos].l == l && seg[pos].r == r)
 80     {
 81         seg[pos].lazy += val;
 82         return ;
 83     }
 84     pushDown(pos);
 85
 86     int mid=seg[pos].mid();
 87     if(r <= mid)
 88         Update(l,r,ls(pos),val);
 89     else if(l > mid)
 90         Update(l,r,rs(pos),val);
 91     else
 92     {
 93         Update(l,mid,ls(pos),val);
 94         Update(mid+1,r,rs(pos),val);
 95     }
 96 }
 97 void Find(int u,int v,int val)
 98 {
 99     while(top[u] != top[v])///u,v不在同一条重链上
100     {
101         if(dep[top[u]] > dep[top[v]])
102             swap(u,v);
103
104         Update(tid[top[v]],tid[v],1,val);///让u,v一步一步靠到同一条重链上
105         v=fa[top[v]];
106     }
107     ///return 语句根据题意而定
108     ///再此题中,u==v时就是单点更新
109 //    if(u == v)
110 //        return ;
111     if(dep[u] > dep[v])
112         swap(u,v);
113     ///这次不是tid[son[u]],因为上次是边权存在了儿子节点里
114     Update(tid[u],tid[v],1,val);
115 }
116 void DFS1(int u,int f,int depth)
117 {
118     fa[u]=f;
119     siz[u]=1;
120     dep[u]=depth;
121     for(int i=head[u];~i;i=G[i].next)
122     {
123         int v=G[i].to;
124         if(v == f)
125             continue;
126
127         DFS1(v,u,depth+1);
128
129         siz[u] += siz[v];
130         if(son[u] == -1 || siz[v] > siz[son[u]])
131             son[u]=v;
132     }
133 }
134 void DFS2(int u,int anc,int &k)
135 {
136     tid[u]=++k;
137     rid[k]=u;
138     top[u]=anc;
139     if(son[u] == -1)
140         return ;
141     DFS2(son[u],anc,k);
142
143     for(int i=head[u];~i;i=G[i].next)
144     {
145         int v=G[i].to;
146         if(v != fa[u] && v != son[u])
147             DFS2(v,v,k);
148     }
149 }
150 void Solve()
151 {
152     DFS1(1,0,0);
153     int k=0;
154     DFS2(1,1,k);
155     buildSegTree(1,k,1);
156
157     char order[10];
158     while(q--)
159     {
160         scanf("%s",order);
161         if(order[0] == 'Q')
162         {
163             int u;
164             scanf("%d",&u);
165             printf("%d\n",Query(tid[u],1));///单点查询,查询u营地当前的人数
166         }
167         else
168         {
169             int u,v,val;
170             scanf("%d%d%d",&u,&v,&val);///区间更新,更新营地[u,v]人数 +val
171             if(order[0] == 'D')
172                 val=-val;///人数减少
173             Find(u,v,val);
174         }
175     }
176 }
177 void Init()
178 {
179     num=0;
180     mem(head,-1);
181     mem(son,-1);
182 }
183 int main()
184 {
185     while(~scanf("%d%d%d",&n,&m,&q))
186     {
187         Init();
188         for(int i=1;i <= n;++i)
189             scanf("%d",a+i);
190         for(int i=1;i <= m;++i)
191         {
192             int u,v;
193             scanf("%d%d",&u,&v);
194             addEdge(u,v);
195             addEdge(v,u);
196         }
197         Solve();
198     }
199     return 0;
200 }

View Code

转载于:https://www.cnblogs.com/violet-acmer/p/9723863.html

hdu 3966(树链剖分+线段树区间更新)相关推荐

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

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

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

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

  3. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  4. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

  5. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

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

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

  7. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  8. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  9. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  10. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

最新文章

  1. Python是如何一步步成为热门编程语言的?
  2. 问到ConcurrentHashMap不要再提Segment了
  3. Nginx站点缓存设置
  4. 链接标签(HTML)
  5. 重置 Mac 上的 NVRAM 或 PRAM
  6. 403 for URL: http://www.terracotta.org/kit/reflector
  7. 12306bycloud,免费开源抢票软件,无需安装,全平台可用
  8. Intelligent driver model(IDM)
  9. 小武与SSD的相遇笑死我了!
  10. 2016.3.30 OneZero站立会议
  11. 小案例 JavaScript-简易五子棋
  12. 【Proteus仿真】Arduino UNO+uln2003驱动步进电机+按键启保停正反转控制
  13. 查看oracle版本及补丁,查看oracle版本和补丁
  14. 计数问题:1~n中x出现了多少次?
  15. word插入Java代码
  16. 恒定积自动做市--兑换比例,滑点,平均成本,资金进出对价格影响
  17. Revit族加密工具分享
  18. 头一回见!提升10倍效率,阿里给业务校验平台插上了AI的翅膀
  19. 【VBA研究】如何防止用户关闭窗体
  20. 远程无法连接到oracle数据库服务器,无法连接到远程Oracle数据库(11g)

热门文章

  1. java 实现一套流程管理、流转的思路(伪工作流) 【仅供参考】
  2. bzoj 1151: [CTSC2007]动物园zoo
  3. 数据机构与算法:书籍介绍
  4. ie8 的断字/断行 bug
  5. 迷你计算机笔记本,迷你笔记本电脑我选择了它,性能不错还超轻便携
  6. (43)FPGA时序逻辑与组合逻辑(时序逻辑)
  7. (36)Verilog HDL关系运算:大于、小于、等于
  8. FPGA时钟激励编写(方法二)
  9. java scanner类 构造器,Java Scanner类
  10. mysql库存自动更新_秒杀库存需不需要实时更新到mysql?