HDU3966 Aragorn’s Story

本文介绍了一种利用树状数组进行单点查询和更新的算法,并通过实例展示了如何构建和使用树状数组来优化查询过程。适用于解决特定类型的图论问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接
这题查找为单点查找,故可以用树状数组来维护。

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,q,tot,label,a[50010],Next[100010],head[100010],tree[100010],dep[50010],son[50010],size[50010],fa[50010];
int tid[50010],top[50010],f[50010];
bool visit[50010];
void swap(int &i,int &j)
{
    int t=i;i=j;j=t;
}
void Add(int x,int y)
{
    tot++;
    Next[tot]=head[x];
    head[x]=tot;
    tree[tot]=y;
}
void dfs(int x,int father,int depth)
{
    visit[x]=true;dep[x]=depth;son[x]=0;size[x]=1;fa[x]=father;
    int maxsize=0 ;
    for (int i=head[x];i;i=Next[i])
    if (!visit[tree[i]])
    {
        dfs(tree[i],x,depth+1);
        size[x]+=size[tree[i]];
        if (size[tree[i]]>maxsize)
        {
            son[x]=tree[i];
            maxsize=size[tree[i]];
        }
    }
}
void dfs1(int x,int ancestor)
{
    visit[x]=true;top[x]=ancestor;label++;tid[x]=label;
    if (son[x]!=0) dfs1(son[x],ancestor);
    for (int i=head[x];i;i=Next[i])
        if (!visit[tree[i]]) dfs1(tree[i],tree[i]); 
}
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int d)
{
    for (int i=x;i<=n;i+=lowbit(i)) f[i]+=d;
}
int get(int x)
{
    int ans=0;
    for (int i=x;i>=1;i-=lowbit(i)) ans+=f[i];
    return ans;
}
int query_it(int x,int y)
{
    return get(x);//单点查询,所以这里x=y; 
}
void change_it(int x,int y,int d)
{
    update(x,d);
    update(y+1,-d);
}
int query(int x,int y)
{
    int ans=0;
    while (top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        ans+=query_it(tid[top[x]],tid[x]);//此题查找是单点,故树状数组可以实现 
        x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y);
    ans+=query_it(tid[x],tid[y]);
    return ans;
}
void change(int x,int y,int d)
{
    while (top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        change_it(tid[top[x]],tid[x],d);
        x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y);
    change_it(tid[x],tid[y],d);
}
int main()
{
    while (scanf("%d%d%d",&n,&m,&q)!=EOF)
    {
        tot=0;label=0;
        for (int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=0,head[i]=0;
        int x,y,z;
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            Add(x,y);Add(y,x);
        }
        for (int i=1;i<=n;i++) visit[i]=false;
        dfs(1,0,1);
        for (int i=1;i<=n;i++) visit[i]=false;
        dfs1(1,1);
        for (int i=1;i<=n;i++) change_it(tid[i],tid[i],a[i]);
        char s[5];
        for (int i=1;i<=q;i++)
        {
            scanf("%s",s);
            if (s[0]=='Q') 
            {
                scanf("%d",&x);
                printf("%d\n",query(x,x));
            }
            if (s[0]=='I')
            {
                scanf("%d%d%d",&x,&y,&z);
                change(x,y,z);
            }
            if (s[0]=='D')
            {
                scanf("%d%d%d",&x,&y,&z);
                change(x,y,-z);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值