[uoj576]服务调度
先考虑一个子问题:仅有一个询问且无修改
对每一种颜色的贡献分类讨论,结论:最远的点一定这些点集中(任意一组)最远点对中的两个点(选择较远的一个)
证明:设$dis(x,y)$为$x$到$y$的距离,$deep_{x}$表示以$k$为根时$x$的深度
假设这个点集中最远点为$(x,y)$,而最深的点为$z$,且$deep_{z}$严格大于$deep_{x}$和$deep_{y}$
一个显然的性质:$deep_{lca(x,y)}\le deep_{x},deep_{y}$
考虑$w=lca(x,y,z)$,若$z=w$与$deep_{z}>deep_{x},deep_{y}$矛盾,因此假设$z$在$w$的某个儿子$w_{z}$中
当若$x$和$y$都在$w_{z}$的子树中显然$lca(x,y,z)$可以为$w_{z}$,因此必然存在一个点在其子树外,不妨设为是$x$,则$lca(x,z)=w$,必然有$deep_{w}\le deep_{lca(x,y)}$
考虑此时$dis(x,z)$与$dis(x,y)$,通过lca的形式展开,由于$deep_{z}>deep_{y}$且$deep_{w}\le deep_{lca(x,y)}$,因此$dis(x,z)>dis(x,y)$,与$(x,y)$为最远点对矛盾
通过合并的方式(即不断插入一个点,三个点两两求$dis$)求出每一个点集的最远点对$(x,y)$,这一部分可以做到$o(n\log_{2}n)$
进一步的,不妨假设$deep_{x}\ge deep_{y}$(此时的$deep$为以1为根),通过倍增找到$z$满足$z$在$x$到$lca(x,y)$的路径上且$dis(x,z)<\lceil\frac{dis(x,y)}{2}\rceil$中$dis(x,z)$最大,那么$k$满足$dis(k,y)>dis(k,x)$当且仅当$k$在$z$子树中
特别的,当$x=y$时令$z=x$,这是为了方便处理,证明比较显然,这里就省略了
接下来,考虑对答案的贡献,分为两部分:
1.$z$的子树中,点$k$的答案加上$deep_{y}+deep_{k}-2depp_{lca(x,y)}$,首尾两个式子都为常数,线段树+dfs序即可,$deep_{k}$通过打“区间加点深度”的标记,再维护区间内所有点深度和即可处理
2.$z$的子树外,考虑$deep_{x}+deep_{k}-2deep_{lca(x,k)}$,前两个式子与上面处理方式相同,考虑第三个式子——
再建一棵线段树,将$fa_{z}$到根的路径打上“减2倍其到父亲的边权”,那么一个点所需要减的就是其到根路径上所有点的和,同时对$z$的子树内部没有影响,因此应对$z$的子树区间加$fa_{z}$的深度
这个考虑在询问时处理,假设询问$k$的子树,对于$k$到根路径上的所有点都会被减小$k$子树大小次,之后对于$k$子树内部的点会被减小子树大小次
分别维护这个值以及这个值乘对应子树大小的两颗线段树就可以处理了,另外链修改需要树链剖分,总复杂度为$o(n\log^{2}n)$
(注意,这样两颗线段树是独立的,也就是对两边的贡献用不同的方式计算)
对于修改,可以看作在某种颜色中插入/删除一个点,对于插入同样直径合并(之后重新修改),删除可以用线段树来做,同样利用直径合并的性质就可以做了(注意修改完直径后都要重新计算贡献)

1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 200005
4 #define ll long long
5 #define L (k<<1)
6 #define R (L+1)
7 #define mid (l+r>>1)
8 #define pii pair<int,int>
9 #define fi first
10 #define se second
11 struct ji{
12 int nex,to,len;
13 }edge[N];
14 int E,n,m,t,x,p,a[N],head[N],d1[N],d2[N],sz[N],son[N],dfn[N],inv_dfn[N],top[N],fa[N][21];
15 int V,pos[N],rt[N],ls[N*40],rs[N*40];
16 vector<int>v[N];
17 pii fd[N*40];
18 ll val[4][N<<2],tag[4][N<<2],f[4][N<<2];
19 void add(int x,int y,int z){
20 edge[E].nex=head[x];
21 edge[E].to=y;
22 edge[E].len=z;
23 head[x]=E++;
24 }
25 void dfs1(int k,int s1,int s2){
26 d1[k]=s1;
27 d2[k]=s2;
28 sz[k]=1;
29 for(int i=1;i<=20;i++)fa[k][i]=fa[fa[k][i-1]][i-1];
30 for(int i=head[k];i!=-1;i=edge[i].nex)
31 if (edge[i].to!=fa[k][0]){
32 dfs1(edge[i].to,s1+1,s2+edge[i].len);
33 sz[k]+=sz[edge[i].to];
34 if ((!son[k])||(sz[son[k]]<sz[edge[i].to]))son[k]=edge[i].to;
35 }
36 }
37 void dfs2(int k,int t){
38 dfn[k]=++x;
39 inv_dfn[x]=k;
40 top[k]=t;
41 if (son[k])dfs2(son[k],t);
42 for(int i=head[k];i!=-1;i=edge[i].nex){
43 int u=edge[i].to;
44 if ((u!=fa[k][0])&&(u!=son[k]))dfs2(u,u);
45 }
46 }
47 int lca(int x,int y){
48 if (d1[x]<d1[y])swap(x,y);
49 for(int i=20;i>=0;i--)
50 if (d1[fa[x][i]]>=d1[y])x=fa[x][i];
51 if (x==y)return x;
52 for(int i=20;i>=0;i--)
53 if (fa[x][i]!=fa[y][i]){
54 x=fa[x][i];
55 y=fa[y][i];
56 }
57 return fa[x][0];
58 }
59 int dis(int x,int y){
60 if ((!x)||(!y))return 0;
61 return d2[x]+d2[y]-2*d2[lca(x,y)];
62 }
63 pii merge(pii x,pii y){
64 int d=0,a[5];
65 pair<int,int>ans=make_pair(0,0);
66 a[0]=0;
67 if (x.fi)a[++a[0]]=x.fi;
68 if (x.se)a[++a[0]]=x.se;
69 if (y.fi)a[++a[0]]=y.fi;
70 if (y.se)a[++a[0]]=y.se;
71 if (a[0]==1)return make_pair(a[1],0);
72 for(int i=1;i<=a[0];i++)
73 for(int j=i+1;j<=a[0];j++){
74 int dd=dis(a[i],a[j]);
75 if (dd>d){
76 d=dd;
77 ans=make_pair(a[i],a[j]);
78 }
79 }
80 return ans;
81 }
82 void update(int &k,int l,int r,int x,int y){
83 if (!k)k=++V;
84 if (l==r){
85 fd[k]=make_pair(y,0);
86 return;
87 }
88 if (x<=mid)update(ls[k],l,mid,x,y);
89 else update(rs[k],mid+1,r,x,y);
90 fd[k]=merge(fd[ls[k]],fd[rs[k]]);
91 }
92 void up(int k){
93 for(int i=0;i<4;i++)f[i][k]=f[i][L]+f[i][R];
94 }
95 void upd(int p,int k,int x){
96 tag[p][k]+=x;
97 f[p][k]+=x*val[p][k];
98 }
99 void down(int k){
100 for(int i=0;i<4;i++)
101 if (tag[i][k]){
102 upd(i,L,tag[i][k]);
103 upd(i,R,tag[i][k]);
104 tag[i][k]=0;
105 }
106 }
107 void build(int k,int l,int r){
108 if (l==r){
109 x=inv_dfn[l];
110 val[0][k]=1;
111 val[1][k]=d2[x];
112 if (x==1)val[2][k]=0;
113 else val[2][k]=d2[x]-d2[fa[x][0]];
114 val[3][k]=val[2][k]*sz[x];
115 return;
116 }
117 build(L,l,mid);
118 build(R,mid+1,r);
119 for(int i=0;i<4;i++)val[i][k]=val[i][L]+val[i][R];
120 }
121 void update(int p,int k,int l,int r,int x,int y,int z){
122 if ((l>y)||(x>r))return;
123 if ((x<=l)&&(r<=y)){
124 upd(p,k,z);
125 return;
126 }
127 down(k);
128 update(p,L,l,mid,x,y,z);
129 update(p,R,mid+1,r,x,y,z);
130 up(k);
131 }
132 ll query(int p,int k,int l,int r,int x,int y){
133 if ((l>y)||(x>r))return 0;
134 if ((x<=l)&&(r<=y))return f[p][k];
135 down(k);
136 return query(p,L,l,mid,x,y)+query(p,R,mid+1,r,x,y);
137 }
138 void calc(int k,int p){
139 int x=fd[rt[k]].fi,y=fd[rt[k]].se;
140 if (!x)return;
141 int z;
142 if (!y)z=y=x;
143 else{
144 if (d2[x]<d2[y])swap(x,y);
145 z=x;
146 int d=(dis(x,y)+1)/2;
147 for(int i=20;i>=0;i--)
148 if (d2[x]-d2[fa[z][i]]<d)z=fa[z][i];
149 }
150 update(0,1,1,n,dfn[z],dfn[z]+sz[z]-1,p*(d2[y]-2*d2[lca(x,y)]));
151 update(0,1,1,n,1,dfn[z]-1,p*d2[x]);
152 update(0,1,1,n,dfn[z]+sz[z],n,p*d2[x]);
153 update(1,1,1,n,1,n,p);
154 update(0,1,1,n,dfn[z],dfn[z]+sz[z]-1,2*p*d2[fa[z][0]]);
155 z=fa[z][0];
156 while (z>1){
157 update(2,1,1,n,dfn[top[z]],dfn[z],-2*p);
158 update(3,1,1,n,dfn[top[z]],dfn[z],-2*p);
159 z=fa[top[z]][0];
160 }
161 }
162 ll query(int k){
163 ll ans=0;
164 for(int i=0;i<4;i++)
165 if (i!=2)ans+=query(i,1,1,n,dfn[k],dfn[k]+sz[k]-1);
166 int x=sz[k];
167 k=fa[k][0];
168 while (k>1){
169 ans+=x*query(2,1,1,n,dfn[top[k]],dfn[k]);
170 k=fa[top[k]][0];
171 }
172 return ans;
173 }
174 int main(){
175 scanf("%d%d%d",&n,&t,&m);
176 for(int i=1;i<=n;i++){
177 scanf("%d",&a[i]);
178 v[a[i]].push_back(i);
179 pos[i]=v[a[i]].size();
180 }
181 memset(head,-1,sizeof(head));
182 fa[1][0]=1;
183 for(int i=2;i<=n;i++)scanf("%d",&fa[i][0]);
184 for(int i=2;i<=n;i++){
185 scanf("%d",&x);
186 add(fa[i][0],i,x);
187 }
188 dfs1(1,0,0);
189 x=0;
190 dfs2(1,1);
191 build(1,1,n);
192 for(int i=1;i<=n;i++)update(rt[a[i]],1,n+m,pos[i],i);
193 for(int i=1;i<=t;i++)calc(i,1);
194 for(int i=1;i<=m;i++){
195 scanf("%d%d",&p,&x);
196 if (p==2)printf("%lld\n",query(x));
197 else{
198 calc(a[x],-1);
199 update(rt[a[x]],1,n+m,pos[x],0);
200 calc(a[x],1);
201 scanf("%d",&a[x]);
202 calc(a[x],-1);
203 v[a[x]].push_back(x);
204 pos[x]=v[a[x]].size();
205 update(rt[a[x]],1,n+m,pos[x],x);
206 calc(a[x],1);
207 }
208 }
209 }
[uoj576]服务调度的更多相关文章
- Apache DolphinScheduler 2.X保姆级源码解析,中国移动工程师揭秘服务调度启动全流程
2022年1月,科学技术部高新技术司副司长梅建平在"第六届中国新金融高峰论坛"上表示,当前数据量已经大大超过了处理能力的上限,若信息技术仍然是渐进式发展,则数据处理能力的提升将远远 ...
- 基于netty轻量的高性能分布式RPC服务框架forest<上篇>
工作几年,用过不不少RPC框架,也算是读过一些RPC源码.之前也撸过几次RPC框架,但是不断的被自己否定,最近终于又撸了一个,希望能够不断迭代出自己喜欢的样子. 顺便也记录一下撸RPC的过程,一来作为 ...
- 使用C#开发计划任务调度服务
在系统运维中常常需要定期去跑一些计划任务,比如扫描服务器监控其性能.检查SQL Server作业是否正常.监控MQ队列是否存在堵塞现象等.如果使用Windows计划任务调度,一来管理起来就比较松散,二 ...
- 基于java工程开发RMI服务端
ServiceRegist.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Service ...
- LBPL--基于Asp.net、 quartz.net 快速开发定时服务的插件化项目
LBPL 这一个基于Asp.net. quartz.net 快速开发定时服务的插件化项目 由于在实际项目开发中需要做定时服务的操作,大体上可以理解为:需要动态化监控定时任务的调度系统. 为了实现快速开 ...
- 基于 Docker 的微服务架构实践
本文来自作者 未闻 在 GitChat 分享的{基于 Docker 的微服务架构实践} 前言 基于 Docker 的容器技术是在2015年的时候开始接触的,两年多的时间,作为一名 Docker 的 D ...
- Spring Cloud微服务Ribbon负载均衡/Zuul网关使用
客户端负载均衡,当服务节点出现问题时进行调节或是在正常情况下进行 服务调度.所谓的负载均衡,就是当服务提供的数量和调用方对服务进行 取舍的调节问题,在spring cloud中是通过Ribbon来解决 ...
- 服务调用框架DataStrom
根据以前的命名服务,从新构建了下服务框架: 结构模式:c-center-s; 1.服务端: 服务端启动,讲自己的IP,端口注册到注册中心节点(master),然后注册自己的处理类(需要继承对应接口); ...
- 朱晔的互联网架构实践心得S2E4:小议微服务的各种玩法(古典、SOA、传统、K8S、ServiceMesh)
十几年前就有一些公司开始践行服务拆分以及SOA,六年前有了微服务的概念,于是大家开始思考SOA和微服务的关系和区别.最近三年Spring Cloud的大火把微服务的实践推到了高潮,而近两年K8S在容器 ...
随机推荐
- Java(31)泛型和可变参数
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15228443.html 博客主页:https://www.cnblogs.com/testero ...
- 手摸手教你用 yapi-to-typescript生成Yapi的TypeScript数据类型
一 背景 现代社会比较重视效率,本着这个思想宗旨,能用工具自动高效做的事情,就不要低质量的勤奋.yapi-to-typescript就是一款自动生成接口请求与响应的typescript数据类型定义的工 ...
- jmeter基础功能及认识
1.基础知识: JMeter是免费开源的,纯java开发的性能测试工具,可以测试静态和动态的资源,例如:静态文件.java服务小程序.CGI脚本.java对象.数据库.FTP服务器.邮件服务器和Per ...
- LeetCode:链表专题
链表专题 参考了力扣加加对与链表专题的讲解,刷了些 leetcode 题,在此做一些记录,不然没几天就没印象了 出处:力扣加加-链表专题 总结 leetcode 中对于链表的定义 // 定义方式1: ...
- 2021.10.15考试总结[NOIP模拟77]
\(n=40\)考虑\(meet \;in \;the \;middle\) 某个元素有关的量只有一个时考虑转化为树上问题 对暴力有自信,相信数据有梯度 没了 UPD:写了个略说人话的. T1 最大或 ...
- 为什么用于开关电源的开关管一般用MOS管而不是三极管
区别: 1.MOS管损耗比三极管小,导通后压降理论上为0. 2.MOS管为电压驱动型,只需要给电压即可,意思是即便串入一个100K的电阻,只要电压够,MOS管还是能够导通. 3.MOS管的温度特性要比 ...
- 从零开始的DIY智能家居 - 基于 ESP32 的土壤湿度传感器
前言 自从上次做了那个 甲醛传感器 和 水浊度传感器 之后开始尝到智能家居的甜头了,这两东西有没有用我不知道,但是没事的时候掏出手机瞄两眼,看着就让人很安心( ̄︶ ̄). 于是懒惰的我开始琢磨把给植物浇 ...
- 让Visual Studio x64 支持 __asm内联汇编
目录 让Visual Studio x64 支持 __asm内联汇编 Intel Parallel Studio XE 2016安装 设置Interl C++ Compiler 使VS x64支持内联 ...
- pycharm基本使用python的注释语法
pychram基本使用 1.主题选择 file settings Editor color Scheme 2.pycharm切换解释器 file settings Project Python Int ...
- 『与善仁』Appium基础 — 5、常用ADB命令(二)
目录 9.查看手机运行日志 (1)Android 日志 (2)按级别过滤日志 (3)按 tag 和级别过滤日志 (4)日志格式 (5)清空日志 10.获取APP的包名和启动名 方式一: 方式二: 11 ...