codeforces 258-E. Little Elephant and Tree 线段树,离线

         给一个节点数为n的树,m个操作,每个操作包涵两个数a,b,第i次操作时,向节点a及其子树,节点b及其子树的数据序列中添加i。m次操作完成后,对于每个节点,查询这棵树上有多少个节点与当前节点至少包涵一个相同数。

         首先对子树操作的话,先对树做dfs并编号,这样某节点的子树节点的编号一定是一个连续的区间,并记录一下每个节点子树节点编号的范围,这样操作就是一个线段树的区间更新了。

         对于操作,可以开个数组或者向量,que[i],保存下所有与i同时操作的节点,这样在查询节点i的时候,先执行que[i]所有的操作,求一下此时有多少个节点被覆盖就行了。查询的时候依然是按dfs序查询,并且一个节点查询结束后要恢复数据。

         另外,还有一个坑,数据给的时候并没有保证边a,b一定是a指向b..只保证了1一定是根...所以还是要存成无向图,然后从1开始dfs...

        

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <queue>
#include <stack>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r
using namespace std;
typedef long long ll;
const int maxn=300000+100;
int x,y;
struct link_edge
{
    int v,next;
}edge[maxn];
int en;
int g[maxn];
int ct[maxn];
struct node
{
    int id,pre;
    int l,r;
    int data;
}tree[maxn];
vector<int>que[maxn];
int n,m,p,q;
int id;
int ans[maxn];
struct segmenttree
{
    int add[maxn<<2];
    int dt[maxn<<2];

    void init()
    {
        memset(dt,0,sizeof dt);
        memset(add,0,sizeof add);
    }
    void pushup(int id,int m)
    {
        if (add[id])
        {
            dt[id]=m;
            return;
        }
        else if (m==1) dt[id]=0;
        else dt[id]=dt[id<<1]+dt[id<<1|1];
    }
    void modify(int L,int R,int id,int l,int r,int c)
    {
        if (L==l && R==r)
        {
            add[id]+=c;
            pushup(id,r-l+1);
            return;
        }
        int m=(l+r)>>1;
        if (R<=m) modify(L,R,lson,c);
        else if (L>m) modify(L,R,rson,c);
        else {
            modify(L,m,lson,c); modify(m+1,R,rson,c);
        }
        pushup(id,r-l+1);
    }
}sgt;
void dfs(int i,int pre)
{
    tree[i].id=id;
    for (int j=g[i]; j!=-1; j=edge[j].next)
    {
        if (edge[j].v==pre) continue;

        id++;
        dfs(edge[j].v,i);
    }
}
void dfs_find(int i,int &minn,int &maxx,int pre)
{
    int k;
    minn=tree[i].id;
    maxx=tree[i].id;
    for (int j=g[i]; j!=-1; j=edge[j].next)
    {
        k=edge[j].v;
        if (k==pre) continue;
        dfs_find(k,tree[k].l,tree[k].r,i);
//        minn=min(minn,min(tree[k].l,tree[k].id));
        maxx=max(maxx,tree[k].r);
    }
    if (minn==999999999) minn=tree[i].id;
}
void work(int u,int pre)
{

    for (int i=0; i<que[u].size(); i++)
    {
        int v=que[u][i];
        sgt.modify(tree[v].l,tree[v].r,1,1,n,1);
    }
    ans[u]+=sgt.dt[1];
    if (ans[u]) ans[u]--;
    for (int j=g[u]; j!=-1; j=edge[j].next)
    {
        if (edge[j].v==pre) continue;
        work(edge[j].v,u);
    }
    for (int i=0; i<que[u].size(); i++)
    {
        int v=que[u][i];
        sgt.modify(tree[v].l,tree[v].r,1,1,n,-1);
    }
}
int main()
{
//    freopen("in.txt","r",stdin);
    memset(g,-1,sizeof g);
    memset(ans,0,sizeof ans);
    en=0;
    scanf("%d%d",&n,&m);
    for (int i=1; i<n; i++)
    {
        scanf("%d%d",&x,&y);
        edge[en].v=y;
        edge[en].next=g[x];
        g[x]=en;
        en++;

        edge[en].v=x;
        edge[en].next=g[y];
        g[y]=en;
        en++;

    }
    tree[1].id=1;
    id=1;
    dfs(1,-1);
    dfs_find(1,tree[1].l,tree[1].r,-1);
//    for (int i=1; i<=n; i++)
//    cout<<tree[i].id<<" "<<tree[i].l<<" "<<tree[i].r<<endl;
    sgt.init();
    for (int i=1; i<=m; i++)
    {
        scanf("%d%d",&x,&y);
        que[x].push_back(x);
        que[x].push_back(y);
        que[y].push_back(x);
        que[y].push_back(y);
    }
    work(1,-1);
    for(int i=1; i<=n; i++) cout<<ans[i]<<" ";
    cout<<endl;
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值