ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang

Posted 6262369sss

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang相关的知识,希望对你有一定的参考价值。

题目链接:https://nanti.jisuanke.com/t/31451

题意:给出一棵有n个点的树,每个点的初始值都是0,m次查询,如果op==1,那么后面接两个数字,表示把第a层的点的值增加b,如果op==2,那么后面接一个数a,表示查询以点a为根节点的这颗子树的所有点的值的和,输出这个值。

思路:因为n,m都可能达到1e5,因为要查找一棵树所有点的和,并且还要修改,如果用树结构查找肯定不方便,那么我们可以用DFS序把树转化为线性结构,用每个点的DSF序来表示这个点,那么查找的时候一棵子树就是一个连续区间,那么我们就可以用树状数组来查找一段区间的和,如果只用树状数组的单点更新,那么极端情况下某一层的点数非常多,更新就会超时;为了解决某一层点非常多并且要更新的情况,我们就可以使用分块的思想来减少更新所需的时间。把所有的层分成大块(点非常多)和小块(点比较少),如果是小块,我们就用树状数组来处理它,更新时暴力更新这一层所有点。如果是大块,我们就用标记数组来记录该层增加的值,因为我们用树的DFS序来代表点,并且DFS序是升序的的,我们就可以用二分查找每个大块来计算目标子树的和。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<set>
#include<cstdio>
#include<string>
#include<deque> 
using namespace std;
typedef long long LL;
#define eps 1e-8
#define INF 0x3f3f3f3f
#define maxn 100005
/*struct point{
    int u,w;
};
bool operator <(const point &s1,const point &s2)
{
    if(s1.w!=s2.w)
    return s1.w>s2.w;
    else
    return s1.u>s2.u;
}*/
struct node{
    int v,next;
}edge[maxn*2];
int head[maxn],L[maxn],R[maxn],pre[maxn];//L[i]和R[i]数组表示i点DFS序的左右边界,pre[i]数组记录i的父亲,这里用来判断有没有走过 
LL c[maxn],up[maxn];//c数组就是树状数组,up数组用来记录点数很多的层数(大块)的增加值 
int n,m,k,r,cnt,Time,max_deep,block;//Time就是DFS序,max_deep记录最大的层数,block用来分块 
vector<int>ve[maxn];//ve[deep]记录在第deep层的点 
vector<int>vv; //vv存大块所在的层 
void init()
{
    fill(head,head+maxn-1,-1);
    fill(pre,pre+maxn-1,0);
    fill(c,c+maxn-1,0);
    fill(up,up+maxn-1,0);
    for(int i=0;i<=n;i++)
    ve[i].clear();
    vv.clear();
    Time=cnt=max_deep=0;
    block=sqrt(n);
}
void DFS(int u,int deep)
{
    L[u]=++Time;//记录左边界 
    max_deep=max(max_deep,deep);
    ve[deep].push_back(Time);//把u点的DFS序值存入第deep层,我们用DFS序把把树转化为线性,然后用树状数组求区间和 
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
    
        int v=edge[i].v;
        if(pre[v])
        continue;
        pre[v]=u;
        DFS(v,deep+1);
    }
    R[u]=Time;//存右边界,注意Time不要加,因为一个点不用记录多个DFS序 
}
void add(int u,int v)
{
    edge[++cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt; 
}
int lowbit(int x)
{
    return x&(-x);
}
void Add(int x,int b)//树状数组单点更新 
{
    for(int i=x;i<=n;i+=lowbit(i))
    c[i]+=b;
}
LL sum(int x)//树状数组求区间和 
{
    if(x<=0)
    return 0;
    LL ans=0;
    while(x>0)
    {
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        pre[1]=-1;
        DFS(1,0);//u,depth
        for(int i=0;i<=max_deep;i++)//把大块存进vv数组 
        {
            if(ve[i].size()>block)
            vv.push_back(i);
        }
        int op;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&op);
            if(op==1)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                if(ve[a].size()>block)//如果a层是大块 
                {
                    up[a]+=b;
                }
                else//a层不是大块 
                {
                    for(int i=0;i<ve[a].size();i++)//暴力更新每个点 
                    Add(ve[a][i],b);
                }
            }
            else
            {
                int a; 
                scanf("%d",&a);
                int l=L[a],r=R[a];
                LL ans=sum(r)-sum(l-1);//我们在树状数组里存的是DFS序,求和是根据DFS序来求和 
                for(int i=0;i<vv.size();i++)//遍历所有大块来寻找属于子树的值 
                {
                    int idx=vv[i];
                    ans+=(upper_bound(ve[idx].begin(),ve[idx].end(),r)-lower_bound(ve[idx].begin(),ve[idx].end(),l))*up[idx];
                }
                printf("%lld
",ans);
            }
        }
    }
    return 0;
}

 

以上是关于ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang的主要内容,如果未能解决你的问题,请参考以下文章

ACM-ICPC 2018 沈阳赛区网络预赛

ACM-ICPC 2018 沈阳赛区网络预赛

ACM-ICPC 2018 沈阳赛区网络预赛 F. Fantastic Graph

ACM-ICPC 2018 沈阳赛区网络预赛 K. Supreme Number

ACM-ICPC 2018 沈阳赛区网络预赛 F. Fantastic Graph (贪心)

ACM-ICPC 2018 沈阳赛区网络预赛 KSupreme Number