题目链接、
题目描述:
小P最近在玩Civilization V,游戏的地图是一棵树,树的每个节点都可以当作战场,刚开始每个节点的战斗加成为0
现在小P拥有两种人员:
一种是工人,每个工人会有一个起点u和终点v,工人可以使u−>v路径上每个节点的战斗加成+1
一种是骑兵,每个战士也有一个起点u和终点v,战士可以选择u−>v路径上任意节点战斗
现有m个工人和q个骑兵,问每个骑兵作战最多可以拥有多少战斗加成
输入格式:
第一行三个整数n,m,q
接下来一行n−1个数,第i个数fi表示第i+1个节点的父亲
接下来m行,每行两个整数u,v,表示一个工人
接下来q行,每行两个整数u,v,表示一个骑兵
输出格式
q行,对于每个骑兵,输出他作战最多可以拥有多少战斗加成
样例
样例输入1
5 5 5 1 1 1 4 4 5 4 1 4 3 5 3 4 5 1 3 3 5 1 1 5 2 4 2
样例输出1
3 5 3 5 5
样例输入2
9 5 5 1 2 2 4 5 3 4 6 4 9 4 7 1 7 1 2 2 1 9 9 9 9 3 3 7 7 2 2
样例输出2
1 1 2 2 4
对于15%的数据,保证n,q≤1000
对于另外15%的数据,保证fi=i
对于另外10%的数据,保证所有u=v
对于另外10%的数据,保证工人的u=v
对于另外10%的数据,保证骑兵的u=v
对于100%的数据,保证n,q≤500,000且fi≤i
早就想写这个题的博客了,为啥一直没写呢,在找zkw线段树的板子,一直找不到有解释清楚的(对于我来说,大佬的解释看不懂qew),(对了,关于那个ppt,里面代码是错的,就这样还有人把代码完完整整的抄下来,然后贴出来了,还tm好几千访问量,下面也没有说错的,我比着那代码都写自闭了)
终于在御坂美琴o((≧▽≦o) ╮( ̄▽ ̄")╭找到了能看懂的
嗯,找zkw线段树的原因是因为我的线段树t了,但是某人的线段树加inline卡常过去了
这题正解应该是线段树维护区间之后st表预处理,但是,既然zkw线段树能过为啥不去学一下呢
树剖不不多讲了,就是个板子,了解的话去,这里
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5+7;
int read(){int c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();if(c == '-')Nig = -1,c = getchar();while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();return Nig*x;}
#define read read()
//链式前向星
int head[maxn],to[maxn<<1],nex[maxn<<1],cnt = 1,n,m,q;
void add(int u,int v){to[cnt] = v,nex[cnt] = head[u],head[u] = cnt++;}
//链式前向星
int son[maxn],id[maxn],fa[maxn],tot,dep[maxn],siz[maxn],top[maxn];
int A[maxn],N;
int tree[maxn<<2];
void push_up(int x,ll Mx = 0){
Mx = max(tree[x],tree[x^1]);
tree[x] -= Mx,tree[x^1] -= Mx;
tree[x>>1] += Mx;
}
void build(int n){
for(N=1;N<n+2;N<<=1);
//for(int i=1;i<=n;++i) tree[N+i]=A[i];
//for(int i=N-1;i;--i)tree[i] = max(tree[i<<1],tree[i<<1|1]);
//for(int i=N+n;i;i--)tree[i] -= tree[i>>1];
}
void update(int s,int t,ll C){
for(s=N+s-1,t=N+t+1;s^t^1;s>>=1,t>>=1){
if(~s&1) tree[s^1]+=C;
if( t&1) tree[t^1]+=C;
push_up(s),push_up(t);
}
while(s>1)push_up(s),s>>=1;
}
int query(int s,int t,int Lans = 0,int Rans = 0){
s += N,t += N;
if(s != t){
for(;s^t^1;s>>=1,t>>=1){
Lans += tree[s];
Rans += tree[t];
if(~s&1) Lans = max(Lans,tree[s^1]);
if( t&1) Rans = max(Rans,tree[t^1]);
}
}
int ans = max(Lans+tree[s],Rans+tree[t]);
while(s>1) ans += tree[s>>=1];
return ans;
}
void dfs1(int u,int Fa,int deep){
dep[u] = deep,fa[u] = Fa,siz[u] = 1;
int maxnson = -1;
for(int i=head[u];i;i=nex[i]){
int y = to[i];
if(y == Fa)continue;
dfs1(y,u,deep+1);
siz[u] += siz[y];
if(siz[y] > maxnson)
son[u] = to[i],maxnson = siz[y];
}
}
void dfs2(int u,int tp){
id[u] = ++tot;
top[u] = tp;
if(!son[u])return;
dfs2(son[u],tp);
for(int i=head[u];i;i=nex[i]){
if(to[i] == fa[u] || to[i] == son[u])continue;
dfs2(to[i],to[i]);//轻儿子有自己的想法
}
}
void upRange(int x,int y,int val){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(id[top[x]],id[x],val);
x = fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
update(id[x],id[y],val);
}
int qRange(int x,int y,int ans = 0){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans = max(ans,query(id[top[x]],id[x]));
x = fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
return max(ans,query(id[x],id[y]));
}
int main(){
//freopen("CV.in","r",stdin);
//freopen("CV.out","w",stdout);
n = read,m = read,q = read;
for(int i=1,u;i<=n-1;i++){
u = read;
add(u,i+1),add(i+1,u);
}
dfs1(1,0,1);
dfs2(1,1);
build(n);
while(m--){
int u,v;
u = read,v = read;
upRange(u,v,1);
}
while(q--){
int u,v;
u = read,v = read;
printf("%d\n",qRange(u,v));
}
return 0;
}