zoukankan      html  css  js  c++  java
  • ACM-ICPC 2018 沈阳赛区网络预赛 J树分块

     J. Ka Chang

    Given a rooted tree ( the root is node 11 ) of NN nodes. Initially, each node has zero point.

    Then, you need to handle QQ operations. There're two types:

    1 L X1 L X: Increase points by XX of all nodes whose depth equals LL ( the depth of the root is zero ). (x leq 10^8)(x108)

    2 X2 X: Output sum of all points in the subtree whose root is XX.

    Input

    Just one case.

    The first lines contain two integer, N,QN,Q. (N leq 10^5, Q leq 10^5)(N105,Q105).

    The next n-1n1 lines: Each line has two integer aa,bb, means that node aa is the father of node bb. It's guaranteed that the input data forms a rooted tree and node 11 is the root of it.

    The next QQ lines are queries.

    Output

    For each query 22, you should output a number means answer.

    样例输入

    3 3
    1 2
    2 3
    1 1 1
    2 1
    2 3

    样例输出

    1
    0

    题目来源

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

    首先这是一个原题,你需要更新深度为x的值,每次仅仅查询子树就可以,用线段树的话,需要更新的太多的

    要树分块,打上time标记,每个数据太多不能暴力更新,单独列出来

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100005;
    vector<int>G[N];
    vector<int>pos[N];
    vector<int>vec;
    int L[N],R[N];
    int tot,n,m,lim=500;
    long long s[N],c[N];
    void dfs(int now,int deep)
    {
        L[now]=++tot;//一块的左标记
        pos[deep].push_back(L[now]);
        for(auto X:G[now])dfs(X,deep+1);
        R[now]=tot;//右标记,这个内全是其子树
        return;
    }
    void add(int x,int d)
    {
        for(;x<=n;x+=x&-x)c[x]+=d;
    }
    long long sum(int x)
    {
        long long ans=0;
        for(;x>0;x-=x&-x)ans+=c[x];
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,u,v;i<n;i++)
            scanf("%d%d",&u,&v),G[u].push_back(v);
        dfs(1,0);
        for(int i=0;i<=n;i++)
            if(pos[i].size()>lim)vec.push_back(i);
        for(int i=0,op,x,y;i<m;i++)
        {
            scanf("%d%d",&op,&x);
            if(op==1)
            {
                scanf("%d",&y);
                if(pos[x].size()<=lim)
                    for(auto X:pos[x])add(X,y);//小于所给块大小,直接树状数组更新
                else s[x]+=y;//大于的直接扔进去等更新
            }
            else
            {
                long long ans=sum(R[x])-sum(L[x]-1);//查询所有小块的值,多余的进行下面的更新
                 for(auto X:vec)
                    ans+=(upper_bound(pos[X].begin(), pos[X].end(),R[x])-lower_bound(pos[X].begin(),pos[X].end(),L[x]))*s[X];
                    //vec的元素不会太多,顶多1e5,直接搞进去更新
                printf("%lld
    ",ans);
            }
        }
    }

    4765: 普通计算姬

    Time Limit: 30 Sec  Memory Limit: 256 MB
    Submit: 1481  Solved: 318
    [Submit][Status][Discuss]

    Description

    "奋战三星期,造台计算机"。小G响应号召,花了三小时造了台普通计算姬。普通计算姬比普通计算机要厉害一些。普通计算机能计算数列区间和,而普通计算姬能计算树中子树和。更具体地,小G的计算姬可以解决这么个问题:给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权值和。计算姬支持下列两种操作:
    1 给定两个整数u,v,修改点u的权值为v。
    2 给定两个整数l,r,计算sum[l]+sum[l+1]+....+sum[r-1]+sum[r]
    尽管计算姬可以很快完成这个问题,可是小G并不知道它的答案是否正确,你能帮助他吗?
     

    Input

    第一行两个整数n,m,表示树的节点数与操作次数。
    接下来一行n个整数,第i个整数di表示点i的初始权值。
    接下来n行每行两个整数ai,bi,表示一条树上的边,若ai=0则说明bi是根。
    接下来m行每行三个整数,第一个整数op表示操作类型。
    若op=1则接下来两个整数u,v表示将点u的权值修改为v。
    若op=2则接下来两个整数l,r表示询问。
    N<=10^5,M<=10^5
    0<=Di,V<2^31,1<=L<=R<=N,1<=U<=N
     

    Output

    对每个操作类型2输出一行一个整数表示答案。
     

    Sample Input

    6 4
    0 0 3 4 0 1
    0 1
    1 2
    2 3
    2 4
    3 5
    5 6
    2 1 2
    1 1 1
    2 3 6
    2 3 5

    Sample Output

    16
    10
    9
    BZOJ这个题目也是啊,但是套路不太一样
     
    #include<iostream>
    #include<vector>
    #include<math.h>
    using namespace std;
    #define N 100005
    typedef unsigned long long ll;
    int n,m,q,lim,root,belong[N];
    int L[N],R[N],tot,cnt[N];
    int g[N][320];
    ll c[N+N],sum[N],a[N],tag[N];
    vector<int>G[N];
    void add(int x,int d)
    {
        for(; x<=n; x+=x&-x)c[x]+=d;
    }
    ll Sum(int x)
    {
        ll ans=0;
        for(; x>0; x-=x&-x)ans+=c[x];
        return ans;
    }
    void dfs(int x,int fa)
    {
        L[x]=++tot,add(L[x],a[x]),++cnt[belong[x]],sum[x]=a[x];
        for(int i=1; i<=lim; i++)g[x][i]=cnt[i];
        int l=G[x].size();
        for(int i=0,X;i<l;i++)
        {
            X=G[x][i];
            if(X==fa)continue;
            dfs(X,x);
            sum[x]+=sum[X];
        }
        R[x]=tot,--cnt[belong[x]],tag[belong[x]]+=sum[x];
    }
    ll query(int l,int r)
    {
        ll ans=0;
        for(int i=l;i<=min(r,belong[l]*m);i++)ans+=Sum(R[i])-Sum(L[i]-1);
        if(belong[l]!=belong[r])
        {
            for(int i=(belong[r]-1)*m+1;i<=r;i++)ans+=Sum(R[i])-Sum(L[i]-1);
        }
        for(int i=belong[l]+1;i<=belong[r]-1;i++)ans+=tag[i];
        return ans;
    }
    int main()
    {
        cin>>n>>q;
        m=sqrt(n+0.5);//一块有几个
        for(int i=1; i<=n; i++)cin>>a[i],belong[i]=(i-1)/m+1;
        lim=belong[n];
        for(int i=1,u,v; i<=n; ++i)
        {
            cin>>u>>v;
            if(!u)root=v;
            else G[u].push_back(v),G[v].push_back(u);
        }
        dfs(root,-1);
        for(int i=0,op,u,v; i<q; i++)
        {
            cin>>op>>u>>v;
            if(op==1)
            {
                for(int i=1; i<=lim; i++)tag[i]+=g[u][i]*1LL*(v-a[u]);
                add(L[u],v-a[u]),a[u]=v;
            }
            else cout<<query(u,v)<<"
    ";
        }
        return 0;
    }
  • 相关阅读:
    大数据开发速查表
    静态图像介绍
    get请求如何传递数组参数
    Redis 6.0 新增功能
    JVM 出现 StackOverflowError和OutOfMemoryError的可能
    golang超级mapper包
    dotnet vs java vs go
    [翻译]Jupyter notebook .NET Core 内核预览1
    .NET Core到底有多强?
    .net core 运行时事件(Runtime Events)
  • 原文地址:https://www.cnblogs.com/BobHuang/p/9640218.html
Copyright © 2011-2022 走看看