bzoj 3653 [湖南集训]谈笑风生(线段树合并)

题目链接

首先分析一下题意,会发现有这么一句话

2.a 和 b 都比 c 不知道高明到哪里去了;

思考一下:如果 a a c c 高,说明 a a c c 的祖先,同样 b b c c 的祖先
那么显然** a a b b 肯定都在 c c 到根的路径上**,所以要么 a a b b 的祖先,要么 b b a a 的祖先

先来思考 b b a a 的祖先的情况:

首先 c c 肯定是在 a a 的子树里,有 s i z e [ a ] 1 size[a]-1
然后 b b 的个数有 m i n ( d e e p [ a ] 1 , k ) min(deep[a]-1,k)
所以这一部分的贡献是 ( s i z e [ a ] 1 ) m i n ( d e e p [ a ] 1 , k ) (size[a]-1)*min(deep[a]-1,k)

接着是 a a b b 的祖先的情况

b b a a 子树中距离 a a 点深度 k k 以内的点,每个 c c 点从 b b 点的子树中取。
这一部分的贡献是共有 s i z e [ b ] 1 ( d e e p [ b ] d e e p [ a ] < = k ) \sum size[b]-1(deep[b]-deep[a]<=k)

显然第一部分dfs的时候 O ( 1 ) O(1) 随便搞搞就可以了,重点在第二部分

我们在每个点弄一颗线段树,以深度为下标,记录这个点子树中每个深度对应的 c c 点的个数

到时候只需要查询 d e e p [ a ] + 1 d e e p [ a ] + k deep[a]+1 \rightarrow deep[a]+k 之间的权值和就行了

为了不MLE,可以考虑在dfs的时候将子节点线段树合并到父节点线段树上,然后就写完了

注意要开下longlong…


#include<bits/stdc++.h>
#define lson tr[now].l
#define rson tr[now].r
using namespace std;

struct tree
{
    long long sum;
    int l,r;
}tr[20000010];

struct op
{
    int k,id;
};

int n,m;
int rt[300010],cnt,deep[300010];
long long ans[300010],size[300010];
vector<int> g[300010];
vector<op> gg[300010];

int dfs(int now,int fa,int dep)
{
    deep[now]=dep;
    size[now]=1;
    rt[now]=++cnt;
    for(int i=0;i<g[now].size();i++)
    {
        if(g[now][i]==fa) continue;
        dfs(g[now][i],now,dep+1);
        size[now]+=size[g[now][i]];
    }
}

int push_up(int now)
{
    tr[now].sum=tr[lson].sum+tr[rson].sum;
}

int insert(int &now,int l,int r,int pos,int val)
{
    if(!now) now=++cnt;
    if(l==r)
    {
        tr[now].sum+=val;
        return 0;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
    {
        insert(lson,l,mid,pos,val);
    }
    else
    {
        insert(rson,mid+1,r,pos,val);
    }
    push_up(now);
}

long long query(int now,int l,int r,int ll,int rr)
{
    if(ll>rr) return 0;
    if(ll<=l&&r<=rr) return tr[now].sum;
    int mid=(l+r)>>1;
    if(rr<=mid)
    {
        return query(lson,l,mid,ll,rr);
    }
    else
    {
        if(mid<ll)
        {
            return query(rson,mid+1,r,ll,rr);
        }
        else
        {
            return query(lson,l,mid,ll,mid)+query(rson,mid+1,r,mid+1,rr);
        }
    }
}

int merge(int a,int b,int l,int r)
{
    if(!a) return b;
    if(!b) return a;
    if(l==r)
    {
        tr[a].sum+=tr[b].sum;
        return a;
    }
    int mid=(l+r)>>1;
    tr[a].l=merge(tr[a].l,tr[b].l,l,mid);
    tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);
    push_up(a);
    return a;
}

int dfs2(int now,int fa)
{
    insert(rt[now],1,300000,deep[now],size[now]-1);
    for(int i=0;i<g[now].size();i++)
    {
        if(g[now][i]==fa) continue;
        dfs2(g[now][i],now);
        merge(rt[now],rt[g[now][i]],1,300000);
    }
    for(int i=0;i<gg[now].size();i++)
    {
        int id=gg[now][i].id;
        int k=gg[now][i].k;
        long long sum1=(size[now]-1)*min(deep[now]-1,k);
        long long sum2=query(rt[now],1,300000,deep[now]+1,min(deep[now]+k,300000));
        ans[id]=sum1+sum2;
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    int from,to;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&from,&to);
        g[from].push_back(to);
        g[to].push_back(from);
    }
    int pos,k;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&pos,&k);
        gg[pos].push_back({k,i});
    }
    dfs(1,0,1);
    dfs2(1,0);
    for(int i=1;i<=m;i++)
    {
        printf("%lld\n",ans[i]);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_21829533/article/details/82988680