POJ--3321(dfs序树状转线性+树状数组+vector防超时写法)

地址:http://poj.org/problem?id=3321

题意:

树上有n个位置,初始每个位置都有苹果。以1号为总根

n-1条分叉边

m条询问:

Q:id   以id为根的子树有几个苹果

C:id    id处如果有苹果,摘掉,否则放上一个苹果。

解析:

假设输入的是这么一棵树:

看数据,肯定要前缀和的思想,但是:

假设要询问4号为根的子树,我们要看的是4+8+9,这些序号很难通过前缀和来维护,因为输入的边并不是按顺序输的。

所以,考虑能不能把这些序号重新编排一下,使其能通过前缀和来求?

这里就引入了dfs序

st[],en[],来记录 i 在dfs序里的开始和结束位置

比如以此图为例:

dfs的遍历顺序:1     2   5    6   3     7   4     8    9

(st[i],en[i]):  (1,9)  (2,4)   (3,3)  (4,4)  (5,6)   (6,6)  (7,9)   (8,8)  (9,9)

很好理解,结合树,比如4:(7,9)它在dfs序中以第7个开始,第9个结束。

所以有:

void dfs(int n)
{
    num++;
    st[n]=num;
    for(int i=0;i<vv[n].size();i++)
    {
        dfs(vv[n][i]);
    }
    en[n]=num;
}

剩下的就交给树状数组维护前缀和了,查询一个点,只需要:getsum(en[id])-getsum(st[id]-1)

vector防超时的写法:vector<vector<int> > vv(maxn);

总的代码:

#include <cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<iostream>
using namespace std;
const int maxn =1e5+10;
int st[maxn],en[maxn],vis[maxn],c[maxn];
vector<vector<int> > vv(maxn);
int num=0;
int lowbit(int x)
{
    return x&(-x);
}
void update(int id,int x)
{
    for(int i=id;i<maxn;i+=lowbit(i))
    {
        c[i]+=x;
    }
    return ;
}
int getsum(int id)
{
    int sum=0;
    for(int i=id;i>0;i-=lowbit(i))
        sum+=c[i];
    return sum;
}
void dfs(int n)
{
    num++;
    st[n]=num;
    for(int i=0;i<vv[n].size();i++)
    {
        dfs(vv[n][i]);
    }
    en[n]=num;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        vv[a].push_back(b);
    }
    
    dfs(1);
    for(int i=1;i<=n;i++)
    {
        update(i,1);
        vis[i]=1;
    }
    int m;
    scanf("%d",&m);
    while(m--)
    {    
        char ch[12];
        scanf("%s",ch);
        if(ch[0]=='Q')
        {
            int id;
            scanf("%d",&id);        
            cout<<getsum(en[id])-getsum(st[id]-1)<<endl;
        }
        else
        {
            int id;
            scanf("%d",&id);
            if(vis[id])
            {
                vis[id]=0;
                update(st[id],-1);
            }
            else
            {
                vis[id]=1;
                update(st[id],1);
            }
        }
    }
}

参考自:https://www.cnblogs.com/FrankChen831X/p/10800106.html  十分感谢!

原文地址:https://www.cnblogs.com/liyexin/p/13074188.html