poj 3321(带时间戳 + 区间统计)

题目描述:

给定一颗树,求某个节点的子树的val值之和

可以用树的前序遍历给每一个节点编号,从而可以确定一个节点的子树的范围,这样就可以进行直接在区间上进行统计了。

vector < int > Map[maxN]写成typedef vector <int> INT; vector <INT> Map(maxN);就不超时了。

线段树

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#define LL long long
using namespace std;
//线段树
//区间每点增值,求区间和
const int maxN = 110000;
struct node
{
    int lt, rt;
    int val;
}tree[4*maxN];


//向上更新
void pushUp(int id)
{
    tree[id].val = tree[id<<1].val + tree[id<<1|1].val;
}

//建立线段树
void build(int lt, int rt, int id)
{
    tree[id].lt = lt;
    tree[id].rt = rt;
   // tree[id].val = 1;//每段的初值,根据题目要求
    if (lt == rt)
    {
        tree[id].val=1;
        return;
    }
    int mid = (lt+rt)>>1;
    build(lt, mid, id<<1);
    build(mid+1, rt, id<<1|1);
    pushUp(id);
}

//增加区间内每个点固定的值
void add(int lt, int rt, int id)
{
    if (lt <= tree[id].lt && rt >= tree[id].rt)
    {
        if(tree[id].val==1)
            tree[id].val=0;
        else
            tree[id].val=1;
        return;
    }
    int mid = (tree[id].lt+tree[id].rt)>>1;
    if (lt <= mid)
        add(lt, rt, id<<1);
    if (rt > mid)
        add(lt, rt, id<<1|1);
    pushUp(id);
}

//查询某段区间内的和
int query(int lt, int rt, int id)
{
    if (lt <= tree[id].lt && rt >= tree[id].rt)
        return tree[id].val;
    int mid = (tree[id].lt+tree[id].rt)>>1;
    int ans = 0;
    if (lt <= mid)
        ans += query(lt, rt, id<<1);
    if (rt > mid)
        ans += query(lt, rt, id<<1|1);
    return ans;
}


struct NODE
{
    int cnt,l,r;
}a[maxN];
typedef vector<int > INT;
vector<INT > Map(maxN);
int vis[maxN];
int number;
void dfs(int fa)
{
    for(int i=0;i<Map[fa].size();i++)
    {
        int son=Map[fa][i];
        if(vis[son]==0)
        {
            a[son].cnt=++number;
            a[son].l= number;
            vis[son]=1;
            dfs(son);
            a[son].r=number;
        }
    }
}
void init()
{
    for(int i=0;i<maxN;i++)
        Map[i].clear();
}
int main()
{
   // freopen("test.txt","r",stdin);
    int n,m;
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n-1;i++)
        {
            int from,to;
            scanf("%d%d",&from,&to);
            Map[from].push_back(to);
            Map[to].push_back(from);
        }
        number=1;
        memset(vis,0,sizeof(vis));
        a[1].cnt=1;
        a[1].l=1;
        vis[1]=1;

        dfs(1);

        a[1].r=number;

        build(a[1].l,a[1].r,1);
        //for(int i=1;i<=9;i++)
        // printf("%d %d %d\n",a[i].cnt,a[i].l,a[i].r);
        int M;
        scanf("%d",&M);
        char str[5];   int id;
        while(M--)
        {
            scanf("%s%d",str,&id);
            //printf("%s\n",str);
            if(str[0]=='Q')
            {
                printf("%d\n",query(a[id].l,a[id].r,1) );
            }
            if(str[0]=='C')
            {
                add(a[id].cnt,a[id].cnt,1);
            }
        }
    }
    return 0;
}

 

树状数组

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#define LL long long
using namespace std;
const int maxN = 110000;
int n;
//树状数组
int C[maxN],A[maxN];
int lowbit(int x)
{
    return x&(-x);
}
int sum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=C[x]; x-=lowbit(x);
    }
    return ret;
}
void update(int x,int pls)
{
    int d;
    if(pls==0)
    {
        if(A[x]==0)
        d=1;
        if(A[x]==1)
        d=-1;
    }
    else
        d=1;
    A[x]+=d;
    while(x<=n)
    {
        C[x]+=d; x+=lowbit(x);
    }
}
struct NODE
{
    int cnt,l,r;
}a[maxN];
typedef vector<int>  INT;
vector < INT >   Map(maxN);
int vis[maxN];
int number;
void dfs(int fa)
{
    for(int i=0;i<Map[fa].size();i++)
    {
        int son=Map[fa][i];
        if(vis[son]==0)
        {
            a[son].cnt=++number;
            a[son].l= number;
            vis[son]=1;
            dfs(son);
            a[son].r=number;
        }
    }
}
void init()
{
    for(int i=0;i<maxN;i++)
        Map[i].clear();
}
int main()
{
    //freopen("test.txt","r",stdin);
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n-1;i++)
        {
            int from,to;
            scanf("%d%d",&from,&to);
            Map[from].push_back(to);
            Map[to].push_back(from);
        }
        number=1;
        memset(vis,0,sizeof(vis));
        a[1].cnt=1;
        a[1].l=1;
        vis[1]=1;

        dfs(1);

        a[1].r=number;
        memset(C,0,sizeof(C));
        memset(A,0,sizeof(A));
        for(int i=1;i<=n;i++)
            update(i,1);
        int M;
        scanf("%d",&M);
        char str[5];   int id;
        while(M--)
        {
            scanf("%s%d",str,&id);
            if(str[0]=='Q')
            {
                printf("%d\n",sum(a[id].r) -sum(a[id].l-1) );
            }
            if(str[0]=='C')
            {
                 update(a[id].cnt,0);
            }
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/xianbin7/p/4868213.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值