Wannafly挑战赛4-dfs序&线段树|搜索&思维|BIT-树的距离

14 篇文章 0 订阅
9 篇文章 0 订阅

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 <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
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;
    queue<pair<int,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;i<m;i++){
         scanf("%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<<s7ums[i]<<" "<<siz[i]<<"??len"<<lens[i]<<endl;
     }*/
     scanf("%d",&n);
     while(n--){
          scanf("%d%d",&x,&k);
         bfs(x,k);
     }
    return 0;
}

线段树代码是别人的。还有一个bit的。 那个类写的特别骚气qwq

#include <bits/stdc++.h>
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].maxx<v) return 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 <bits/stdc++.h>
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();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值