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;
    }
  • 相关阅读:
    入门菜鸟
    FZU 1202
    XMU 1246
    Codeforces 294E Shaass the Great 树形dp
    Codeforces 773D Perishable Roads 最短路 (看题解)
    Codeforces 814E An unavoidable detour for home dp
    Codeforces 567E President and Roads 最短路 + tarjan求桥
    Codeforces 567F Mausoleum dp
    Codeforces 908G New Year and Original Order 数位dp
    Codeforces 813D Two Melodies dp
  • 原文地址:https://www.cnblogs.com/BobHuang/p/9640218.html
Copyright © 2011-2022 走看看