cf#381D 树状数组+二分
2016-12-02 11:08
369 查看
http://codeforces.com/contest/740/problem/D
之前就学过一些树状数组,但仅限于单点修改,区间查询。。
树状数组到底是怎么回事 搞懂树状数组原理
大神说的很清楚辣,简单的说就是开一个新数组利用二进制记录原数组某几个的和,最后实现快速的求任意区间的和,突然想起当年图卡的1248码。
当知道了树状数组是求区间和很快很方便之后,对于区间修改,单点询问i,可以也这么用,求一个数组的前I项和就是i改变了多少,如何操作呢?
假如在ai~aj上+5
那c【i】+= 5 c【j+1】-= 5 是不是就满足了i到j的所有数都+5,因为每个数字在这个区间中的都被+了一次5
记住树状数组是快速求和其实就好想多了
这道题呢outputstandard output
Alyona has a tree with n vertices. The root of the tree is the vertex 1. In each vertex Alyona wrote an positive integer, in the vertex i she wrote ai. Moreover, the girl wrote a positive integer to every edge of the tree (possibly, different integers on different edges).
Let’s define dist(v, u) as the sum of the integers written on the edges of the simple path from v to u.
The vertex v controls the vertex u (v ≠ u) if and only if u is in the subtree of v and dist(v, u) ≤ au.
Alyona wants to settle in some vertex. In order to do this, she wants to know for each vertex v what is the number of vertices u such that v controls u.
还有就是区间修改区间查询
http://www.wonter.net/archives/%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84-%E5%8C%BA%E9%97%B4%E6%9B%B4%E6%96%B0-%E5%8C%BA%E9%97%B4%E6%9F%A5%E8%AF%A2.html
sum(x) = a[1] + a[2] + … + a[x] + delta[1] * x + delta[2] * (x - 1) + delta[3] * (x - 2) + … + delta[x] =segma(a[i]) + segma(delta[i] * (x - i + 1)) (1 <= i <= x)=segma(a[i]) + segma(delta[i]) * (x + 1) - segma(delta[i] * i)
delta[i] 和 delta[i] * i 这两个数组会变化,我们可以开两个数组。 c1 表示 delta[i],c2 表示 delta[i] * i 所以上面的更新,根据 c1 和 c2 的定义,因为 delta[a] += d, delta[b + 1] -= d,所以我们只需要将 c1[a] += d, c1[b + 1] -= d,c2[a] += d * a, c2[b + 1] -= d * (b + 1),就可以了。 查询的话,就只需要求前缀和就好了。
之前就学过一些树状数组,但仅限于单点修改,区间查询。。
树状数组到底是怎么回事 搞懂树状数组原理
大神说的很清楚辣,简单的说就是开一个新数组利用二进制记录原数组某几个的和,最后实现快速的求任意区间的和,突然想起当年图卡的1248码。
当知道了树状数组是求区间和很快很方便之后,对于区间修改,单点询问i,可以也这么用,求一个数组的前I项和就是i改变了多少,如何操作呢?
假如在ai~aj上+5
那c【i】+= 5 c【j+1】-= 5 是不是就满足了i到j的所有数都+5,因为每个数字在这个区间中的都被+了一次5
记住树状数组是快速求和其实就好想多了
这道题呢outputstandard output
Alyona has a tree with n vertices. The root of the tree is the vertex 1. In each vertex Alyona wrote an positive integer, in the vertex i she wrote ai. Moreover, the girl wrote a positive integer to every edge of the tree (possibly, different integers on different edges).
Let’s define dist(v, u) as the sum of the integers written on the edges of the simple path from v to u.
The vertex v controls the vertex u (v ≠ u) if and only if u is in the subtree of v and dist(v, u) ≤ au.
Alyona wants to settle in some vertex. In order to do this, she wants to know for each vertex v what is the number of vertices u such that v controls u.
题意:
给你一棵树,u是v的祖先且uv距离小于等于a【v】时代表着u能控制v,问每个u能控制多少vtip:
这个题用lca可以,我还没做,先说说树状数组的做法,首先预处理出来每个点和root的距离,再dfs一遍记录下来这条链上高度h的点是哪个,树状数组的下标也是h,二分高度,找到距离可以的最下面的点,这个时候从这个点的father到找到的这个点都是可以控制当前v的(区间修改),每次dfs结束所有孩子时统计这个点控制了多少点(单点询问),然后这个h的树状数组位置要归零,至于怎么归零,相当于c【h】-= 和,c【h+1】+=和。这个题就结束了,记得注意long long#include <cstdio> #include <iostream> #include <cstring> using namespace std; #define LL long long const int maxn = 2*1e5+100; int n,root,tot,first[maxn],arr[maxn],ans[maxn]; LL dist[maxn],treea[maxn],au[maxn]; struct node{ int v,dis,next; }edges[maxn]; void add(int u,int v,int d){ edges[tot].v = v;edges[tot].dis = d; edges[tot].next = first[u];first[u] = tot++; } void init(){ tot = 0; memset(first,-1,sizeof(first)); for(int i = 1; i <= n ;i++) scanf("%I64d",&au[i]); for(int i = 2 ; i <= n;i++){ int s,d; scanf("%d%d",&s,&d); add(s,i,d); } dist[1] = 0; } int lowerbound(int size,LL key,int pos){ int l =1 ,r = size; while(l < r){ int m = l+(r-l)/2; if(treea[m] < key){ l = m+1; pos = l; } else{ r = m; pos = r; } } // printf("pos = %d\n",pos); return pos; } int lowbit(int x){ return x&(-x); } void add(int pos,int num){ for(int i = pos ; i < maxn ;i += lowbit(i)) arr[i] += num; } int getsum(int pos){ int sum = 0; for(int i = pos ; i > 0 ; i-= lowbit(i)){ sum += arr[i]; } return sum; } void dfs(int root){ for(int k = first[root] ; k != -1 ;k = edges[k].next){ dist[edges[k].v] = dist[root]+edges[k].dis; dfs(edges[k].v); } } void sov(int root ,int step){ treea[step] = dist[root]; for(int k = first[root] ; k != -1 ;k = edges[k].next){ sov(edges[k].v,step+1); } if(step == 1){ ans[root] = getsum(1); return; } // for(int i = 1 ; i <= step ; i++) // printf("treea[%d] = %I64d,step = %d,au[%d]-dist[%d] = %d- %I64d = %I64d\n",i,treea[i],step,root,root,au[root],dist[root],-au[root]+dist[root]); int pos = lowerbound(step,dist[root]-au[root],step); if(pos != step){ add(pos,1); add(step,-1); } ans[root] = getsum(step); //printf("ans[%d] = %d\n",root,ans[root]); add(step,-ans[root]); add(step+1,ans[root]); } void print(){ for(int i = 1 ; i <= n ;i++ ) printf("%d%c",ans[i],i == n?'\n':' '); } int main(){ scanf("%d",&n); init(); dfs(1); sov(1,1); print(); }
还有就是区间修改区间查询
http://www.wonter.net/archives/%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84-%E5%8C%BA%E9%97%B4%E6%9B%B4%E6%96%B0-%E5%8C%BA%E9%97%B4%E6%9F%A5%E8%AF%A2.html
sum(x) = a[1] + a[2] + … + a[x] + delta[1] * x + delta[2] * (x - 1) + delta[3] * (x - 2) + … + delta[x] =segma(a[i]) + segma(delta[i] * (x - i + 1)) (1 <= i <= x)=segma(a[i]) + segma(delta[i]) * (x + 1) - segma(delta[i] * i)
delta[i] 和 delta[i] * i 这两个数组会变化,我们可以开两个数组。 c1 表示 delta[i],c2 表示 delta[i] * i 所以上面的更新,根据 c1 和 c2 的定义,因为 delta[a] += d, delta[b + 1] -= d,所以我们只需要将 c1[a] += d, c1[b + 1] -= d,c2[a] += d * a, c2[b + 1] -= d * (b + 1),就可以了。 查询的话,就只需要求前缀和就好了。
相关文章推荐
- POJ 2892 Tunnel Warfare || HDU 1540(树状数组+二分 || 线段树的单点更新+区间查询)
- hdu------(4302)Holedox Eating(树状数组+二分)
- 【POJ2104】【整体二分+树状数组】区间第k大
- POJ - 2182 D - Lost Cows 暴力//树状数组加二分
- ACM学习历程—51NOD 1685 第K大区间2(二分 && 树状数组 && 中位数)
- ZOJ 3635 Cinema in Akiba (树状数组+二分)
- POJ 2182 Lost Cows(树状数组+二分)
- 树状数组 ( Binary Indexed Tree,BIT,二分索引树 )
- ACM学习历程—HDU5592 ZYB's Premutation(逆序数 && 树状数组 && 二分)(BestCoder Round #65 1003)
- [POJ2182]Lost Cows(树状数组,二分)
- UVa 11610 Reverse Prime(树状数组+二分)
- [BZOJ2738]矩阵乘法 整体二分+二维树状数组
- Hdu 5493 Queue【伸展树/二分+树状数组】
- codeforces_652D. Nested Segments(树状数组、二分)
- [BZOJ4009][HNOI2015]接水果-整体二分-树状数组-扫描线
- 二分树状数组-洛谷P1168 中位数
- HDU 2852 KiKi's K-Number【 树状数组 二分 】
- Zoj 3635 <树状数组+二分>
- 树状数组+二分||线段树 HDOJ 5493 Queue
- HDU 5493(树状数组+二分)