您的位置:首页 > 其它

FZU 2176 easy problem (DFS序+树状数组)

2016-05-02 18:08 176 查看
对于一颗树,dfs遍历为每个节点标号,在进入一个树是标号和在遍历完这个树的子树后标号,那么子树所有的标号都在这两个数之间,是一个连续的区间。(好神奇~~~)

这样每次操作一个结点的子树时,在每个点的开始结束两个点标记一下就可以,用树状数组求前缀和就可知道每个点的值。

这道题虽然很麻烦(dep[y]-dep[x])%k 。但是注意到K很小(1<=k<=5),可以维护k个树状数组。

提交时编译器选GUN C++迷之RE。。。换Visual C++

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define clr(x,c) memset(x,c,sizeof(x))
using namespace std;
typedef long long ll;

const int N = 50005;

vector<int> g
;
vector<int> lev[5];
ll bit[5]
;
int d
, l
, r
;
int n, m, k;
int cnt;

void dfs(int u, int fa, int dep)
{
d[u] = dep;
l[u] = ++cnt;
lev[dep%k].push_back(l[u]);
for (unsigned i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if (v == fa) continue;
dfs(v, u, dep+1);
}
r[u] = cnt;
}

void init()
{
for (int i = 0; i <= n; ++i) g[i].clear();
for (int i = 0; i < k; ++i) lev[i].clear();
clr(bit, 0); clr(l, 0); clr(r, 0); clr(d, 0);
cnt = 0;
}

int lb(int j, int x)
{
return lower_bound(lev[j].begin(), lev[j].end(), x) - lev[j].begin() + 1;
}

int lowbit(int x) { return x & -x; }

void add(int j, int pos, int val)
{
while (pos <= lev[j].size() ) {
bit[j][pos] += val;
pos += lowbit(pos);
}
}

ll sum(int j, int pos)
{
ll ans = 0;
while (pos) {
ans += bit[j][pos];
pos -= lowbit(pos);
}
return ans;
}

int main()
{
int t;
int cas = 0;
scanf("%d", &t);
while (t--) {
printf("Case#%d:\n", ++cas);
scanf("%d%d%d", &n, &m, &k);
init();
int u, v;
for (int i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0, 0);
while (m--) {
int ch, x, v;
scanf("%d%d", &ch, &x);

if (ch == 1) {
scanf("%d", &v);
for (int i = 0; i < k; ++i) {
int j = (i + d[x]) % k;
int ls = lb(j, l[x]), rs = lb(j, r[x]+1);
add(j, ls, (i + 1) * v);
add(j, rs, (-1 - i) * v);
}
} else {
int j = d[x] % k;
int s = lb(j, l[x]);
printf("%lld\n", sum(j, s));
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: