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;
}

原文地址:https://www.cnblogs.com/mcq1999/p/11420127.html

时间: 2024-08-08 03:37:43

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

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序来表示这个点,那么查找的时候一棵

ACM-ICPC 2018 南京赛区网络预赛 G Lpl and Energy-saving Lamps(模拟+线段树)

https://nanti.jisuanke.com/t/30996 题意 每天增加m个灯泡,n个房间,能一次性换就换,模拟换灯泡过程.询问第几天的状态 分析 离线做,按题意模拟.比赛时线段树写挫了..导致不断超时,我太弱了.每次询问符合要求的最左边的点. #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #i

【ACM-ICPC 2018 沈阳赛区网络预赛 I】Lattice&#39;s basics in digital electronics

[链接] 我是链接,点我呀:) [题意] 每个单词的前缀都不同. 不能更明示了... 裸的字典树. 模拟一下.输出一下就ojbk了. [题解] #include <bits/stdc++.h> #define LL long long #define rep1(i,a,b) for (int i = a;i <= b;i++) #define rep2(i,a,b) for (int i = a;i >= b;i--) #define all(x) x.begin(),x.end(

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

"Oh, There is a bipartite graph.""Make it Fantastic." X wants to check whether a bipartite graph is a fantastic graph. He has two fantastic numbers, and he wants to let all the degrees to between the two boundaries. You can pick up sev

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

A prime number (or a prime) is a natural number greater than 11 that cannot be formed by multiplying two smaller natural numbers. Now lets define a number NN as the supreme number if and only if each number made up of an non-empty subsequence of all

ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer (最大生成树+LCA求节点距离)

ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer J. Maze Designer After the long vacation, the maze designer master has to do his job. A tour company gives him a map which is a rectangle. The map consists of N \times MN×M little squares. That is to say, the h

ACM-ICPC 2018 南京赛区网络预赛 J.Sum

Sum A square-free integer is an integer which is indivisible by any square number except 11. For example, 6 = 2 \cdot 36=2⋅3 is square-free, but 12 = 2^2 \cdot 312=22⋅3 is not, because 2^222 is a square number. Some integers could be decomposed into

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

A. Gudako and Ritsuka 留坑 B. Call of Accepted 留坑 C. Convex Hull 留坑 D. Made In Heaven 留坑 E. The cake is a lie 留坑 F. Fantastic Graph 留坑 G. Spare Tire 留坑 H. Hamming Weight 留坑 I. Lattice's basics in digital electronics 留坑 J. Ka Chang 留坑 K. Supreme Number

线性素数筛 ACM-ICPC 2018 南京赛区网络预赛 J Sum

https://www.jisuanke.com/contest/1555?view=challenges 题意: 题解:写完都没发现是个积性函数233 想法就是对x分解质因数,f(x)就是2^k,其中k是x分解结果中次数为一的质因子个数.如果有某个次数大于等于3,f(x)==0; 这样明显会TLE 所以就想一个递推的方法. 于是魔改了一下线性筛. #include<iostream> #include<cstdlib> #include<cstdio> #includ