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

题目描述

乐乐做了个梦,梦见自己当了国王。乐乐王国有 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\n",(ask(1,l[x],r[x],x)%mod+mod)%mod);
        }
    }
    return 0;
}
posted @ 2020-07-18 14:18  牛大了的牛大  阅读(222)  评论(0编辑  收藏  举报