[入门组模拟赛[难]]城市管理
题目描述
乐乐做了个梦,梦见自己当了国王。乐乐王国有 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; }