Apple Tree

题目连接

  • 题意:
    给n个点(1-n)的树,1为根节点,每个点初始值为1。q次操作:1、C操作:每次给一个标号x,将x节点的值取非  2、Q操作:给x,求x子树的点值之和
  • 分析:
    这个题目关键在于将树上的节点放到一维来处理,这样就可以用树状数组或者线段树来解决了。处理时使用dfs,对每个节点都进行编号。
树状数组:

const int MAXN = 100001;

int nxt[MAXN << 1], val[MAXN << 1], head[MAXN], tot = 0;
void adj_init(int n)
{
    REP(i, n)
        head[i] = -1;
    tot = 0;
}
void adj_ins(int u, int v)
{
    val[tot] = v;
    nxt[tot] = head[u];
    head[u] = tot++;
}

int dfs_clock;
int lft[MAXN], rht[MAXN];
void dfs(int u, int fa)
{
    lft[u] = dfs_clock++;
    for (int i = head[u]; ~i; i = nxt[i])
    {
        if (val[i] != fa)
            dfs(val[i], u);
    }
    rht[u] = dfs_clock - 1;
}

int tree[MAXN];
inline int lowbit(int x)
{
    return x & (-x);
}
inline void add(int p, int v)
{
    for (; p < MAXN; p += lowbit(p))
        tree[p] += v;
}
inline int sum(int p)
{
    int ret = 0;
    for (; p > 0; p -= lowbit(p))
        ret += tree[p];
    return ret;
}

int ipt[MAXN];
int main()
{
    int n, q;
    while (~RI(n))
    {
        adj_init(n + 1);
        dfs_clock = 1;
        CLR(tree, 0);
        FE(i, 1, n)
            ipt[i] = 1;

        REP(i, n - 1)
        {
            int a, b;
            RII(a, b);
            adj_ins(a, b);
            adj_ins(b, a);
        }
        dfs(1, -1);

        RI(q);
        FE(kase, 1, q)
        {
            char op; int v;
            scanf(" %c %d", &op, &v);
            int l = lft[v], r = rht[v];
            if (op == 'Q')
            {
                WI(r - l + 1 - sum(r) + sum(l - 1));
            }
            else
            {
                int ad = 1;
                if (ipt[v] == 0)
                    ad = -1;
                ipt[v] ^= 1;
                add(l, ad);
            }
        }
    }
    return 0;
}


线段树:
const int MAXN = 100001;

int nxt[MAXN << 1], val[MAXN << 1], head[MAXN], tot = 0;
void adj_init(int n)
{
    REP(i, n)
        head[i] = -1;
    tot = 0;
}
void adj_ins(int u, int v)
{
    val[tot] = v;
    nxt[tot] = head[u];
    head[u] = tot++;
}

int dfs_clock;
int lft[MAXN], rht[MAXN];
void dfs(int u, int fa)
{
    lft[u] = dfs_clock++;
    for (int i = head[u]; ~i; i = nxt[i])
    {
        if (val[i] != fa)
            dfs(val[i], u);
    }
    rht[u] = dfs_clock - 1;
}

#define lson rt << 1
#define rson rt << 1 | 1
struct Node
{
    int l, r, m;
    int sum;
} nd[MAXN << 2];

void pushUP(int rt)
{
    nd[rt].sum = nd[lson].sum + nd[rson].sum;
}

void build(int l, int r, int rt)
{
    nd[rt].l = l; nd[rt].r = r; nd[rt].m = (l + r) >> 1;
    if (l == r)
        nd[rt].sum = 1;
    else
    {
        build(l, nd[rt].m, lson);
        build(nd[rt].m + 1, r, rson);
        pushUP(rt);
    }
}

void add(int p, int v, int rt)
{
    if (nd[rt].l == nd[rt].r)
        nd[rt].sum += v;
    else
    {
        if (p <= nd[rt].m)
            add(p, v, lson);
        else
            add(p, v, rson);
        pushUP(rt);
    }
}

int query(int L, int R, int rt)
{
    if (L <= nd[rt].l && nd[rt].r <= R)
        return nd[rt].sum;
    else
    {
        int ret = 0;
        if (L <= nd[rt].m)
            ret += query(L, R, lson);
        if (R > nd[rt].m)
            ret += query(L, R, rson);
        return ret;
    }
}

int ipt[MAXN];
int main()
{
    int n, q;
    while (~RI(n))
    {
        adj_init(n + 1);
        dfs_clock = 1;
        build(1, n, 1);
        FE(i, 1, n)
            ipt[i] = 1;

        REP(i, n - 1)
        {
            int a, b;
            RII(a, b);
            adj_ins(a, b);
            adj_ins(b, a);
        }
        dfs(1, -1);

        RI(q);
        FE(kase, 1, q)
        {
            char op; int p;
            scanf(" %c %d", &op, &p);
            int l = lft[p], r = rht[p];
            if (op == 'Q')
            {
                WI(query(l, r, 1));
            }
            else
            {
                int ad = -1;
                if (ipt[p] == 0)
                    ad = 1;
                ipt[p] ^= 1;
                add(l, ad, 1);
            }
        }
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值