https://www.nowcoder.com/acm/contest/35/D
dfs序那个方法是标准做法。但是不知道怎么去用线段树搞。
给定一个树(根为1),然后给你 x和k,要求你求x为根的子树中 距离x大于等于k的点的 和。
一看子树,就知道是dfs序。关键是如何搞线段树orBIT ,把距离根节点的值 映射到 线段树上后(线段树的下标意义代表时间。)
维护最大值和最小值和 和(即线段树子树内的和qwq)。 还是没有特别专注这种东西。不错的题。
② 第二种方法,是dfs维护 距离根长度,x子树内的节点和x的距离和。
另外还要维护 fa(每个节点的父亲节点,因为后来用bfs计算的时候可以应用,不然就要麻烦一点)
用bfs计算节点的时候,因为递归性。
(如图,如果一个点距离x点已经大于等于k,那么他的子节点必然,所以我们如果计算好后,直接加就行),否则的话,就要累加距离,然后再进一步的递归计算。
这其实比单纯的bfs要快好多了,因为开始维护的sums数组。
ps:写的其实比较蠢笨。因为u22 这个,直接用x代替就好,累加的永远是和 x的距离qwq。u22永远只能是x。。
#include
#include
#include
#include
using namespace std;
/* 可以通过一个 dfs维护两个变量。
一个 节点距离根节点的 距离len[u].
另一个是 节点内的点距离 节点的距离和 sum[u].
因为我们发现了一个递归的性质,
如果一个点距离 x节点的距离大于等于k。
那么他的子节点也是。
我们可以统计一个长度再bfs里。
*/
typedef long long ll;
const int maxn=2e5*2+200;
int m;
int len;
struct Node{
int to,next,cos;
}node[maxn];
int head[maxn];
void add(int a,int b,int c){
node[len].to=b;
node[len].next=head[a];
node[len].cos=c;
head[a]=len++;
}
ll lens[maxn];
ll sums[maxn];
int siz[maxn];
int fa[maxn];
void init(){
memset(head,-1,sizeof(head));
len=0;
}
void dfs(int u,int fas){
sums[u]=0;
siz[u]=1;//ben jiedian.
for(int i=head[u];i!=-1;i=node[i].next){
int to=node[i].to;
int cost=node[i].cos;
if(to==fas) continue;
fa[to]=u;//这个再bfs的时候有一点用处。
lens[to]=lens[u]+1ll*cost;
dfs(to,u);
siz[u]+=siz[to];
sums[u]+=sums[to]+(1ll*siz[to]*cost);
}
}
void bfs(int x,int k){
ll ans=0;
queueint ,int> >q;
q.push(make_pair(x,x));
while(!q.empty()){
int u=q.front().first;
int u22=q.front().second;
q.pop();
for(int i=head[u];i!=-1;i=node[i].next){
int to=node[i].to;
int cost=node[i].cos;
if(to==fa[u]) continue;
if(lens[to]-lens[u22]>=1ll*k){
ans=ans+(sums[to]+1ll*siz[to]*(lens[to]-lens[u22]));
}
else{
q.push(make_pair(to,u22));
}
}
}
printf("%lld\n",ans);
}
int main()
{ int a,b,x,k,n;
scanf("%d",&m);
init();
for(int i=1;iscanf("%d%d",&a,&b);
add(a,i+1,b);
add(i+1,a,b);
}
dfs(1,-1);
/*for(int i=1;i<=m;i++){
cout<
scanf("%d",&n);
while(n--){
scanf("%d%d",&x,&k);
bfs(x,k);
}
return 0;
}
线段树代码是别人的。还有一个bit的。 那个类写的特别骚气qwq
#include
using namespace std;
typedef long long LL;
const int maxn = 200010;
struct edge{
int to,next;
LL cost;
}E[maxn*2];
int head[maxn], edgecnt;
void init(){
memset(head, -1, sizeof(head));
edgecnt = 0;
}
void add(int u, int v, LL w){
E[edgecnt].to = v, E[edgecnt].next = head[u], E[edgecnt].cost = w, head[u] = edgecnt++;
}
int L[maxn], R[maxn], dfs_clk;
LL a[maxn], d[maxn];
struct node{
int l, r;
LL minn, maxx, sum;
}Tree[maxn<<2];
void dfs(int u, int pre){
L[u] = ++dfs_clk;
for(int i=head[u]; ~i; i=E[i].next){
int v = E[i].to;
if(v == pre) continue;
d[v] = d[u] + E[i].cost;
dfs(v, u);
}
R[u] = dfs_clk;
}
void push_up(int rt){
Tree[rt].maxx = max(Tree[rt*2].maxx, Tree[rt*2+1].maxx);
Tree[rt].minn = min(Tree[rt*2].minn, Tree[rt*2+1].minn);
Tree[rt].sum = Tree[rt*2].sum + Tree[rt*2+1].sum;
}
void build(int l, int r, int rt){
Tree[rt].l = l, Tree[rt].r = r;
if(l == r){
Tree[rt].maxx = Tree[rt].minn = Tree[rt].sum = a[l];
return;
}
int mid = l+r>>1;
build(l, mid, rt*2);
build(mid+1, r, rt*2+1);
push_up(rt);
}
LL query(int L, int R, LL s, LL v, int rt){
if(L<=Tree[rt].l && Tree[rt].r<=R){
if(Tree[rt].minn>=v) return Tree[rt].sum - 1LL*s*(Tree[rt].r-Tree[rt].l+1);
if(Tree[rt].maxxreturn 0;
}
int mid = (Tree[rt].l+Tree[rt].r)/2;
if(R<=mid) return query(L, R, s, v, rt*2);
else if(L>mid) return query(L, R, s, v, rt*2+1);
else return query(L, mid, s, v, rt*2) + query(mid+1, R, s, v, rt*2+1);
}
int main(){
init();
int n;
scanf("%d", &n);
for(int i=2; i<=n; i++){
int p;
LL x;
scanf("%d %lld", &p, &x);
add(p, i, x);
//add(i, p, x);
}
dfs(1, -1);
for(int i=1; i<=n; i++) a[L[i]] = d[i];
build(1, n, 1);
int q;
scanf("%d", &q);
while(q--){
int x;
LL k;
scanf("%d %lld", &x, &k);
LL ans = query(L[x], R[x], d[x], d[x]+k, 1);
printf("%lld\n", ans);
}
return 0;
}
③别人家的BIT
#include
using namespace std;
#define endl "\n"
const int N = 1e6 + 8;
int lt[N], sum, tot, n, q;
long long ans[N];
struct BIT
{
long long a[N];
void insert(int pos, long long val)
{
pos++;
for (int i = pos; i <= n + 1; i += i & (-i)) a[i] += val;
}
long long sigma(int pos)
{
long long res = 0;
for (int i = pos; i > 0; i -= i & (-i)) res += a[i];
return res;
}
long long query(int l, int r)
{
l++; r++;
if (l == 0) return sigma(r);
return sigma(r) - sigma(l - 1);
}
}T1, T2;
struct edge
{
int v, w, nt;
}eg[N << 1];
struct query
{
long long x;
int id, w, size;
long long dis;
bool operator <(const query &b) const
{
return x < b.x;
}
void print()
{
cout << x << " " << id << " " << w << " " << size << " " << dis << endl;
}
}Q[N];
struct node
{
long long dis;
int w, size;
bool operator < (const node &b) const
{
return dis < b.dis;
}
void print()
{
cout << dis << " " << w << " " << size << endl;
}
}a[N];
void add(int u, int v, int w)
{
eg[++sum] = (edge){v, w, lt[u]}; lt[u] = sum;
}
void dfs(int u)
{
a[u].w = ++tot; a[u].size = 1;
for (int i = lt[u]; i; i = eg[i].nt)
{
a[eg[i].v].dis = a[u].dis + eg[i].w;
dfs(eg[i].v);
a[u].size += a[eg[i].v].size;
}
}
void init()
{
cin >> n;
for (int i = 1; i <= n; ++i) lt[i] = 0;
sum = 1; tot = 0;
for (int i = 1; i < n; ++i)
{
int v, w;
cin >> v >> w;
add(v, i + 1, w);
}
dfs(1);
cin >> q;
for (int i = 1; i <= q; ++i)
{
int x, k;
cin >> x >> k;
Q[i].id = i;
Q[i].x = a[x].dis + k;
Q[i].w = a[x].w;
Q[i].size = a[x].size;
Q[i].dis = a[x].dis;
}
sort(Q + 1, Q + q + 1);
sort(a + 1, a + n + 1);
}
void solve()
{
for (int i = q, j = n; i >= 1; --i)
{
while (j > 0 && a[j].dis >= Q[i].x)
{
T1.insert(a[j].w, 1);
T2.insert(a[j].w, a[j].dis);
j--;
}
int num = T1.query(Q[i].w, Q[i].w + Q[i].size - 1);
long long sum = T2.query(Q[i].w, Q[i].w + Q[i].size - 1);
ans[Q[i].id] = sum - num * Q[i].dis;
}
for (int i = 1; i <= q; ++i) cout << ans[i] << endl;
}
int main()
{
cin.sync_with_stdio(0);
init();
solve();
}