列表

详情


NC212478. 柠檬树

描述

柠檬树上柠檬果,柠檬树下你和我❥(^_-)。

这是一棵有 n 个柠檬的柠檬树,由 n-1 条枝条连接而成。

秋天了,柠檬都成熟了, 牛牛和牛妹准备选一些柠檬送给他们的朋友们。

对于每一个朋友,牛妹会选择第 l-r 个柠檬送给朋友。具体的采摘方法是:选取尽可能少的树枝,使得区间内的柠檬**两两连通**。

牛牛负责派送柠檬,但他的朋友太多啦,他实在是忙的上气不接下气,所以他想让您来帮忙。

输入描述

第一行,输入 n,q ,表示柠檬数和朋友数 。

接下来 n-1 行,每行输入 u 和 v ,表示一条枝条连接了 u 和 v 。

接下来 q 行,每行输入 l 和 r ,表示送给这位朋友第 l-r 个柠檬最少选几根树枝。

输出描述

输出共 q 行,每行输出选取尽可能少的树枝数。

示例1

输入:

5 3
1 2
2 3
3 4
4 5
1 3
1 5
4 5

输出:

2
4
1

说明:

对于第一组询问,至少需要第1条和第2条树枝,这样两条边1-2和2-3能将1和3苹果连接起来。

对于第二组询问,这4条树枝都必须取,此时四条边能将1到5这5个苹果连接起来。

示例2

输入:

5 5
2 1
3 2
2 4
5 4
1 3
4 5
1 3
2 3
2 5

输出:

2
1
2
1
3

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 400ms, 内存消耗: 24864K, 提交时间: 2021-02-04 21:35:04

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,bs=20001;
int n,q,tot,head[N],nex[N<<1],to[N<<1];
int id,son[N],top[N],fa[N],dep[N],len[N],dfn[N];
int L,R;
void add(int u,int v)
{
    to[++tot]=v;nex[tot]=head[u];head[u]=tot;
}
void dfs1(int u,int p)
{
    dep[u]=dep[p]+1;fa[u]=p;
    for(int i=head[u];i;i=nex[i])
    {
        int v=to[i];if(v==p) continue;
        dfs1(v,u);
        len[u]=max(len[u],len[v]);
        if(len[v]>len[son[u]]) son[u]=v;
    }
    len[u]++;
}
void dfs2(int u,int tp)
{
    top[u]=tp;dfn[u]=++id;
    if(son[u]) dfs2(son[u],tp);
    for(int i=head[u];i;i=nex[i])
    {
        int v=to[i];if(dfn[v]) continue;
        dfs2(v,v);
    }
}
int LCA(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]]) u=fa[top[u]];
        else v=fa[top[v]];
    }
    return dep[u]<dep[v]?u:v;
}
int tlca[N<<2];
void buildlca(int l,int r,int k)
{
    if(l==r)
    {
        tlca[k]=l;return;
    }
    int m=l+r>>1;
    buildlca(l,m,k<<1);buildlca(m+1,r,k<<1|1);
    tlca[k]=LCA(tlca[k<<1],tlca[k<<1|1]);
}
int querylca(int l,int r,int k,int x,int y)
{
    if(l>=x&&r<=y) return tlca[k];
    int m=l+r>>1;
    if(x<=m&&y>m) return LCA(querylca(l,m,k<<1,x,y),querylca(m+1,r,k<<1|1,x,y));
    else if(x<=m) return querylca(l,m,k<<1,x,y);
    return querylca(m+1,r,k<<1|1,x,y);
}
vector<pair<int,int>>query[N];
int ans[N],bit[N];
int qsum(int x)
{
    int ans=0;
    while(x) ans+=bit[x],x-=x&-x;
    return ans;
}
void Add(int x,int val)
{
    while(x<=n) bit[x]+=val,x+=x&-x;
}
int t[N<<2];
bool vis[N<<2];
void del(int l,int r,int k)
{
    if(!vis[k]) return;
    vis[k]=false;
    if(t[k])
    {
        Add(t[k],-(r-l+1));
        t[k]=0;
        return;
    }
    int m=l+r>>1;
    del(l,m,k<<1);del(m+1,r,k<<1|1);
}
void update(int l,int r,int k,int x,int y,int id)
{
    if(r<x||l>y) return;
    if(l>=x&&r<=y)
    {
        del(l,r,k);
        t[k]=id;vis[k]=true;
        return;
    }
    int m=l+r>>1;
    if(t[k])
        t[k<<1]=t[k<<1|1]=t[k],vis[k<<1]=vis[k<<1|1]=true,t[k]=0;
    update(l,m,k<<1,x,y,id);
    update(m+1,r,k<<1|1,x,y,id);
    vis[k]=vis[k<<1]|vis[k<<1|1];
}
void Insert(int u)
{
    int id=u;
    Add(u,dep[u]);
    while(u)
    {
        update(1,n,1,dfn[top[u]],dfn[u],id);
        u=fa[top[u]];
    }
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    dfs1(1,0);
    dfs2(1,1);
    buildlca(1,n,1);
    for(int i=1;i<=q;i++)
    {
        int l,r;scanf("%d%d",&l,&r);
        query[r].push_back({l,i});
    }
    for(int i=1;i<=n;i++)
    {
        Insert(i);
        for(pair<int,int>x:query[i])
            ans[x.second]=qsum(i)-qsum(x.first-1)-dep[querylca(1,n,1,x.first,i)];
    }
    for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
}

上一题