题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1103
题目大意:给你一个树,刚开始所有树边边权均为1,不断地将其中的某些边边权改为0,其间问你某个点到根节点之间路径上的边权和。
此题和POJ的Apple Tree很相近。。。
首先DFS生成整棵树的拓扑序,DFS时每个结点i进入的时间l[i]和离开的时间r[i],然后对每次更改操作,维护树状数组即可。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXE 501000
#define MAXV 251000
#define lowbit(x) (x&(-x))
using namespace std;
struct edge
{
int u,v,next;
}edges[MAXE];
int head[MAXV],nCount=0;
int sum[MAXE],cnt=0,l[MAXV],r[MAXV],fa[MAXV]; //l、r是每个结点dfs序的左右区间
int n,m;
bool visit[MAXV];
void AddEdge(int U,int V)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].next=head[U];
head[U]=nCount;
}
void update(int x,int v)
{
while(x<MAXE)
{
sum[x]+=v;
x+=lowbit(x);
}
}
int query(int x)
{
int ans=0;
while(x>0)
{
ans+=sum[x];
x-=lowbit(x);
}
return ans;
}
void dfs(int u) //从点u出发dfs,得到树的拓扑序
{
visit[u]=true;
l[u]=++cnt;
update(cnt,1);
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(!visit[v])
{
fa[v]=u;
dfs(v);
}
}
r[u]=++cnt;
update(cnt,-1);
}
int main()
{
memset(head,-1,sizeof(head));
char cmd[10];
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
AddEdge(a,b);
AddEdge(b,a);
}
dfs(1);
scanf("%d",&m);
for(int i=1;i<=n+m-1;i++)
{
int a,b;
scanf("%s%d",cmd,&a);
if(cmd[0]=='A') //将a-b边边权变为0
{
scanf("%d",&b);
if(fa[a]==b) swap(a,b); //保证b的父亲是a
update(l[b],-1);
update(r[b],1);
}
else
printf("%d\n",query(l[a])-1);
}
return 0;
}
[BZOJ 1103][POI 2007]大都市(DFS求拓扑序+树状数组)
原文:http://blog.csdn.net/qpswwww/article/details/41704091