• [入门组模拟赛[难]]城市管理


    题目描述

    乐乐做了个梦,梦见自己当了国王。乐乐王国有 N 座城市(编号从 1~N,
    首都的编号为 1)。乐乐王国的道路构成树状结构:首都 1 与几个大城市相连,
    这几个大城市又通过道路与一些稍小的城市相连……严格地说,这 N 座城市构
    成一棵有根树(1 为树根),城市 i的管理区域为以 i 为根的子树。
    道路都是双向的。经过每条道路需要收费,从城市 A 到城市 B 的花费为 A
    到 B的简单路径上所有道路的费用之和(不妨称之为城市对(A, B)之间的花费)。
    显然,一棵树上任意两点之间的简单路径(即不能重复经过某个点的路径)是唯
    一的。
    由于物价飞涨,经过一番缜密的思考,乐乐决定重新规划自己国家的道路收
    费。具体来说,他要进行Q个操作,每个操作是如下两种类型:
    INC u v w
    ——表示 u 到 v的路径上,所有的道路的收费增加 w;
    ASK p
    ——表示询问城市 p的管理区域中,所有的“城市对”的花费之和。比如,
    城市 p的管理区域 (即以 p 为根子树) 中有城市 c1, c2, c3, …, cs (这里面包括 p) ,
    询问所有的城市对(c1, c2), (c1, c3), …, (c2, c3), …,(cs-1, cs)的花费之和。
    乐乐把这个问题交给你,快帮帮他吧!

    输入

    第一行输入两个正整数N,Q,分别表示城市的数目和操作的数目。
    接下来有 N – 1 行,第 i 行是两个正整数p[i], c[i],表示城市 p[i]是城市i 的
    父亲结点,且连接 p[i]和 i 的道路的初始收费为 c[i](1≤c[i]≤1000)。
    接下来有 Q行,每行是如下两种类型之一:
    INC u v w (u, v, w 都是整数,且 1≤u, v≤N, 0≤w≤1000,注意 u, v 可能相
    等)
    ASK p (p 是整数,且0≤p≤1000)
    意义如题目所述。

    输出

    对每个 ASK类型的操作,输出所求的答案。请你输出答案对 2018 取模后的
    结果。

    样例输入

    5 5
    1 1
    2 5
    1 2
    2 1
    INC 2 4 2
    INC 3 4 1
    ASK 2
    INC 2 5 3
    ASK 1

    样例输出

    14
    84

    提示

    对于 20%的数据,1≤Q, N≤200;
    对于 40%的数据,1≤Q, N≤5,000;
    对于 70%的数据,1≤Q, N≤50,000,且树的深度(即每个城市到首都经过
    的道路数目最大值)不会太大;
    对于 100%的数据,1≤Q, N≤50,000,树的深度不超过 10000,其他输入数
    据的范围在输入格式中已给出。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=50001;
    const int mod=2018;
    vector<int> e[N];
    int n,m,q,x,y,z,mid,val[N],fa[N],son[N],d[N],siz[N],l[N],r[N],top[N],num[N],len;
    char op[5];
    struct tree{
        int l,r,tag,siz1,siz2,sum1,sum2;
    }t[N*4];
    void dfs1(int k,int dep)
    {
        son[k]=0;
        d[k]=dep;
        siz[k]=1;
        for(int i=0;i<e[k].size();i++)
        {
            dfs1(e[k][i],dep+1);
            siz[k]+=siz[e[k][i]];
            if(siz[e[k][i]]>siz[son[k]])
                son[k]=e[k][i];
        }
    }
    void dfs2(int k,int tp)
    {
        l[k]=++len;
        num[len]=k;
        top[k]=tp;
        if(son[k])
            dfs2(son[k],tp);
        for(int i=0;i<e[k].size();i++)
        {
            if(e[k][i]==son[k]) continue;
            dfs2(e[k][i],e[k][i]);
        }
        r[k]=len;
    }
    void build(int k,int l,int r)
    {
        t[k].l=l,t[k].r=r;
        if(l==r)
        {
            t[k].siz1=siz[num[r]]%mod;
            t[k].siz2=1ll*siz[num[r]]*siz[num[r]]%mod;
            t[k].sum1=1ll*val[num[r]]*siz[num[r]]%mod;
            t[k].sum2=1ll*val[num[r]]*siz[num[r]]*siz[num[r]]%mod;
            return;
        }
        build(2*k,l,(l+r)/2);
        build(2*k+1,(l+r)/2+1,r);
        t[k].sum1=(t[2*k].sum1+t[2*k+1].sum1)%mod;
        t[k].sum2=(t[2*k].sum2+t[2*k+1].sum2)%mod;
        t[k].siz1=(t[2*k].siz1+t[2*k+1].siz1)%mod;
        t[k].siz2=(t[2*k].siz2+t[2*k+1].siz2)%mod;
    }
    void add(int k,int x,int y,int z)
    {
        if(x==t[k].l&&y==t[k].r)
        {
            if(x!=y) t[k].tag+=z;
            t[k].sum1=(t[k].sum1+1ll*t[k].siz1*z%mod)%mod;
            t[k].sum2=(t[k].sum2+1ll*t[k].siz2*z%mod)%mod;
            return;
        }
        if(t[k].tag)
        {
            add(2*k,t[2*k].l,t[2*k].r,t[k].tag);
            add(2*k+1,t[2*k+1].l,t[2*k+1].r,t[k].tag);
            t[k].tag=0;
        }
        if(y<=t[2*k].r) add(2*k,x,y,z);
        else if(x>=t[2*k+1].l) add(2*k+1,x,y,z);
        else
        {
            add(2*k,x,t[2*k].r,z);
            add(2*k+1,t[2*k+1].l,y,z);
        }
        t[k].sum1=(t[2*k].sum1+t[2*k+1].sum1)%mod;
        t[k].sum2=(t[2*k].sum2+t[2*k+1].sum2)%mod;
    }
    int ask(int k,int x,int y,int root)
    {
        if(x==t[k].l&&y==t[k].r)
            return (1ll*t[k].sum1*siz[root]%mod-t[k].sum2+mod)%mod;
        if(t[k].tag)
        {
            add(2*k,t[2*k].l,t[2*k].r,t[k].tag);
            add(2*k+1,t[2*k+1].l,t[2*k+1].r,t[k].tag);
            t[k].tag=0;
        }
        if(y<=t[2*k].r) return ask(2*k,x,y,root);
        if(x>=t[2*k+1].l) return ask(2*k+1,x,y,root);
        return (ask(2*k,x,t[2*k].r,root)+ask(2*k+1,t[2*k+1].l,y,root))%mod;
    }
    void change(int x,int y,int z)
    {
        int ans=0;
        while(top[x]!=top[y])
        {
            if(d[top[x]]<d[top[y]]) swap(x,y);
            add(1,l[top[x]],l[x],z);
            x=fa[top[x]];
        }
        if(x==y) return;
        if(d[x]>d[y]) swap(x,y);
        add(1,l[son[x]],l[y],z);
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=2;i<=n;i++)
        {
            scanf("%d%d",&fa[i],&val[i]);
            e[fa[i]].push_back(i);
        }
        dfs1(1,1);
        dfs2(1,1);
        build(1,1,len);
        for(int i=1;i<=q;i++)
        {
            scanf("%s",op);
            if(strcmp(op,"INC")==0)
            {
                scanf("%d%d%d",&x,&y,&z);
                change(x,y,z);
            }
            if(strcmp(op,"ASK")==0)
            {
                scanf("%d",&x);
                printf("%d
    ",(ask(1,l[x],r[x],x)%mod+mod)%mod);
            }
        }
        return 0;
    }
  • 相关阅读:
    protobuf自解释message
    protobuf编码
    proto3语法
    proto2语法
    protobuf简介
    poi处理大EXCEL文件总结
    POI-处理大Excel文件(xlsx写)
    POI-处理大Excel文件(xlsx)
    POI-处理大Excel文件(xls)
    RedHat 6.4 RHCS GFS2安装
  • 原文地址:https://www.cnblogs.com/LJA001162/p/13335626.html
Copyright © 2020-2023  润新知