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

来源:互联网 发布:熊猫tv送假佛跳墙软件 编辑:程序博客网 时间:2024/06/12 12:22

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();}