【题解】

  每个情报员的危险值val[i]应该是一个分段函数,前面一段是平行于x轴的横线,后面一段是一次函数。我们可以用fx(t)=t-b[x]表示这个一次函数。每次询问一条链上fx(t)大于c的点的个数,也就是问有多少个点满足t-b[x]>c,移项得b[x]<t-c,不等式左边只与点有关,可以当做点权,右边只与询问有关。因此我们可以写没有修改的主席树。

  同时这道题也可以离线后用树状数组写。我们维护某个点到根的链上小于等于某个值的数的个数Cnt,这开一个权值树状数组就可以做到。这样每个询问(x,y)的答案就是Cnt[x]+Cnt[y]-Cnt[lca]-Cnt[fa[lca]]. 我们dfs进行维护,进入这个点的时候在树状数组中加入点权,退出这个点的时候删除点权,同时在每个点计算与这个点有关的答案即可。

  

 #include<cstdio>
#include<algorithm>
#include<queue>
#define N 200010
#define rg register
using namespace std;
int n,m,rt,tot,cnt,ret,last[N],ans[N],ans2[N],fa[N],hvy[N],size[N],top[N],dep[N],t[N],val[N];
vector<int>son[N];
struct rec{
int pos,val,type,pre;
}data[N<<];
inline int read(){
int k=,f=; char c=getchar();
while(c<''||c>'')c=getchar();
while(''<=c&&c<='')k=k*+c-'',c=getchar();
return k*f;
}
void dfs1(int x){
size[x]=; dep[x]=dep[fa[x]]+;
for(rg int i=,s;i<son[x].size();i++){
dfs1(s=son[x][i]); size[x]+=size[s];
if(size[s]>size[hvy[x]]) hvy[x]=s;
}
}
void dfs2(int x,int tp){
top[x]=tp;
if(hvy[x]) dfs2(hvy[x],tp);
for(rg int i=,s;i<son[x].size();i++)
if((s=son[x][i])!=hvy[x]) dfs2(s,s);
}
inline int lca(int x,int y){
int f1=top[x],f2=top[y];
while(f1!=f2){
if(dep[f1]<dep[f2]) swap(x,y),swap(f1,f2);
x=fa[f1]; f1=top[x];
}
return dep[x]<dep[y]?x:y;
}
void dfs(int x){
for(rg int i=val[x];i<=m;i+=(i&-i)) t[i]++;
for(rg int i=last[x];i;i=data[i].pre){
ret=;
for(rg int j=data[i].val-;j>;j-=(j&-j)) ret+=t[j];
ans[data[i].pos]+=data[i].type*ret;
}
for(rg int i=;i<son[x].size();i++) dfs(son[x][i]);
for(rg int i=val[x];i<=m;i+=(i&-i)) t[i]--;
}
int main(){
n=read();
for(rg int i=;i<=n;i++){
fa[i]=read();
if(!fa[i]) rt=i;
son[fa[i]].push_back(i);
}
m=read();
for(rg int i=;i<=n;i++) val[i]=m;
dfs1(rt); dfs2(rt,rt);
for(rg int t=;t<=m;t++){
int opt=read();
if(opt==){
int x=read(),y=read(),c=read(),Lca=lca(x,y);
data[++tot]=(rec){++cnt,t-c,,last[x]}; last[x]=tot;
data[++tot]=(rec){cnt,t-c,,last[y]}; last[y]=tot;
data[++tot]=(rec){cnt,t-c,-,last[Lca]}; last[Lca]=tot;
data[++tot]=(rec){cnt,t-c,-,last[fa[Lca]]}; last[fa[Lca]]=tot;
ans2[cnt]=dep[x]+dep[y]-*dep[Lca]+;
}
else{
int x=read(); if(val[x]==m) val[x]=t;
}
}
dfs(rt);
for(rg int i=;i<=cnt;i++) printf("%d %d\n",ans2[i],ans[i]);
return ;
}

最新文章

  1. 【WP8.1】HttpClient网络请求、进度以及终止
  2. CODEVS 天梯 代码记录
  3. 建立时间和保持时间(setup time 和 hold time)
  4. Gitlab的搭建
  5. plist文件的使用
  6. centos添加PATH环境变量
  7. squid日志配置与轮询
  8. ylbtech-QQ(腾讯)-群
  9. InvokeHelper,让跨线程访问/修改主界面控件不再麻烦(转)
  10. PAT 1047
  11. [js笔记整理]面向对象篇
  12. Integer的疑惑
  13. UnicodeDecodeError: &#39;ascii&#39; codec can&#39;t decode byte
  14. org.codehaus.plexus.archiver.jar.Manifest.write(java.io.PrintWriter)
  15. if语句题目练习
  16. Jenkins进阶-Slave 节点的配置(11)
  17. Spring中 &lt;context:property-placeholder 的使用与解析 .properties 配置文件的加载
  18. Vmware ESXi添加共享磁盘
  19. Web编辑器的使用
  20. 阿里云oracle启动失败

热门文章

  1. POJ1743 Musical Theme 最长重复子串 利用后缀数组
  2. linux下的C语言开发(定时器)
  3. 【158】◀▶ Linux-Bash学习
  4. 如何在 ubuntu 12.04 上安装 skype(转载)
  5. js angular 时间戳转换成日期格式 年月日 yyyy-MM-dd
  6. 商品期货高频交易策略Tick框架
  7. 洛谷 P1433 吃奶酪(记忆化)
  8. 贪心 Codeforces Round #135 (Div. 2) C. Color Stripe
  9. 使用JS分页 &lt;span&gt; beta 3.0 完成封装的分页
  10. T-SQL编程以及常用函数