• ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)


    题意

    链接:https://nanti.jisuanke.com/t/A1998

    给出一个有根树(根是1),有n个结点。初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L(根节点深度为0)的点的值全部增加X。操作2.查询以x为根的子树的结点值得和。其中N,Q<=1e5。

    思路

    因为这题是对某一深度的所有点加x,所以不是树链剖分。

    我们可以先预处理一下dfs序,顺带把d[u]:u的深度、dd[x]:深度为x的点集求出来。

    考虑分块,对某一深度分两种情况:1.这一深度的点的个数<=block;2.这一深度的点的个数>block。

    对于情况1:更新操作我们可以暴力,因为block我是取的sqrt(n),那么更新的复杂度最坏也是O(qlog(n)sqrt(n)),还能接受,毕竟数据不是特别强。

    对于情况2:我们直接将这一层加上x,即add[deep]+=x。

    对于查询操作,我们先线段树计算一下这个点为根的子树的值,当然,线段树只暴力更新了size<=block的层,所以查询也只会查询这些层上的值。我们还要计算一下size>block的层,怎么计算呢?

    我们先定义一个map<ll,ll> M[N],M[u]表示u为根节点的子树的值的和(size>block的层),M可以通过枚举每个点,如果这个点所在层的size>block,这个点就对它的所有父亲都有贡献,所以往上爬,对父亲加上这个点的贡献。所以size>block的层的值我们可以轻松通过M来得到。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define ll long long
    #define int ll
    const int N=200005;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    struct node
    {
        int to,next;
    } eg[N];
    int head[N],tot=0,sum[N<<2],add[N];
    void init()
    {
        memset(head,-1,sizeof(head));
        tot=0;
    }
    void addedge(int u,int v)
    {
        eg[tot].to=v;
        eg[tot].next=head[u];
        head[u]=tot++;
    }
    int in[N],out[N],id=0,q[N],d[N],block,f[N];
    vector<int> dd[N];
    map<ll,ll> M[N];
    void dfs(int x,int fa,int deep)
    {
        q[++id]=x;
        in[x]=id;
        d[x]=deep;
        f[x]=fa;
        dd[deep].push_back(x);
        for(int i=head[x]; ~i; i=eg[i].next)
        {
            if(eg[i].to!=fa)
            {
                dfs(eg[i].to,x,deep+1);
            }
        }
        out[x]=id;
    }
    void pushUp(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]=0;
            return;
        }
        int m=(l+r)>>1;
        build(l,m,rt<<1);
        build(m+1,r,rt<<1|1);
        pushUp(rt);
    }
    void update(int L,int c,int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]+=c;
            return ;
        }
        int m=(l+r)>>1;
        if(m>=L)    update(L,c,l,m,rt<<1);
        else        update(L,c,m+1,r,rt<<1|1);
        pushUp(rt);
    
    }
    int query(int L,int R,int l,int r,int rt)
    {
        if(l>=L&&r<=R)
        {
            return sum[rt];
        }
        int m=(l+r)>>1;
        int ans=0;
        if(m>=L)
            ans+=query(L,R,l,m,rt<<1);
        if(m<R)
            ans+=query(L,R,m+1,r,rt<<1|1);
        return ans;
    }
    ll ask(int rt)
    {
        map<ll,ll>::iterator it=M[rt].begin();
        ll res=0;
        for(;it!=M[rt].end();it++)
        {
            res+=(it->second)*add[it->first];
        }
        return res;
    }
    signed main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int n,q;
        while(cin>>n>>q)
        {
            id=0;
            memset(in,0,sizeof(in));
            memset(out,0,sizeof(out));
            init();
            for(int i=0; i<n-1; i++)
            {
                int a,b;
                cin>>a>>b;
                addedge(a,b);
                addedge(b,a);
            }
            block=sqrt(n);
            dfs(1,0,0);
            build(1,n,1);
            for(int i=1; i<=n; i++)
            {
                if(dd[d[i]].size()>block)
                {
                    int u=i;
                    while(u)
                    {
                        if(!M[u][d[i]])
                            M[u][d[i]]=1;
                        else
                            M[u][d[i]]++;
                        u=f[u];
                    }
                }
            }
        //   for(int i=1;i<=n;i++)
         //       cout<<i<<" "<<in[i]<<" "<<out[i]<<endl;
            while(q--)
            {
                int o,a,b;
                cin>>o>>a;
                if(o==1)
                {
                    cin>>b;
                    if(dd[a].size()>block)
                    {
                        add[a]+=b;
                    }
                    else
                    {
                        int sz=dd[a].size();
                        for(int i=0;i<sz;i++)
                        {
                            int u=dd[a][i];
                            update(in[u],b,1,n,1);
                        }
                    }
                }
                else
                {
    
                    cout<<query(in[a],out[a],1,n,1)+ask(a)<<endl;
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    最新 Cocos2d-x 3.2 开发环境搭建(windows环境下)
    Apache OFbiz entity engine源代码解读
    Android 标签控件
    标准红外遥控的接收程序-松瀚汇编源程序
    uva 10548
    char* 和char[]的差别
    依据波形的转折点文件,转换成波形文件
    spring 中StoredProcedure的使用方法
    JMS的样例
    JavaScript高级编程
  • 原文地址:https://www.cnblogs.com/mcq1999/p/11420127.html
Copyright © 2020-2023  润新知