【问题描述】
Mark Douglas是一名优秀的锻造师。与他优秀的锻造水平不相符,他非常穷,以至于很多好刀都因为缺少素材缺少资金无法打造。
Mark把他有能力锻造的所有n种刀建成了一棵锻造树,除了第1种刀可以直接打造以外,其他的刀都只能从某一种刀加工而来。具体而言,第i种刀只能从第fai种刀加工而来,花费的费用为wi,但是第fai种刀不能由第i种刀逆加工得到。Mark定义一种刀的价值为利用他现有的刀进行打造的花费。他虽然穷,但是眼光很高,价值低于一定值的刀他都看不上。现在有q次询问,每次询问当Mark手里有第u种刀且他能看上的最小价值为k时,他能看上的所有刀的价值和是多少。
【输入格式】
输入文件名为forging.in。
第一行为一个正整数n。
接下来n-1行,每行两个正整数fai wi。
下一行一个正整数q。
接下来q行,每行两个正整数u k。
【输出格式】
输出文件名为forging.out。
输出q行,每行表示一组询问的答案。
输入:
3
1 2
1 3
2
1 3
1 2
输出:
3
5
【数据范围】
对于1~4号测试点(20%):1<=n,q<=1000。
对于1~8号测试点(40%)1<=n,q<=100000,1<=k<=50。
对于9~10号测试点(10%):树的形态为一条链。
对于9~14号测试点(30%):除1号点外其余所有点的度数不超过2。
对于所有测试点(100%)1<=n,q<=100000,1<=k<=1e9,1<=wi<=1000。
首先这道题,我们可以把它看作主席树裸题,也可以看成线段树合并模板;
然而这里所说的是用分块维护树剖;
一开始我们将这个树进行树链剖分,注意,我们并不用线段树来维护,所以只要把树剖的预处理部分写出来就好了;
我们知道树剖的性质(dfs序当然也可以):一个以根节点和它的所有子节点所形成的集合是在一段连续的区间;
那么对于每次询问,在每块里二分位置,把每块里大与这个位置的数都累加到答案中;
注意一个细节:当二分的答案是这个区间的最右端时,一定要特判这个点是否满足条件;
时间复杂度时一个O(nlogn+q*sqrt(n)*logn);
可过,不用离线处理,不用离散化,再大的数据范围也可以这么做;
#include <bits/stdc++.h> #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fipa-sra") #pragma GCC optimize("-ftree-pre") #pragma GCC optimize("-ftree-vrp") #pragma GCC optimize("-fpeephole2") #pragma GCC optimize("-ffast-math") #pragma GCC optimize("-fsched-spec") #pragma GCC optimize("unroll-loops") #pragma GCC optimize("-falign-jumps") #pragma GCC optimize("-falign-loops") #pragma GCC optimize("-falign-labels") #pragma GCC optimize("-fdevirtualize") #pragma GCC optimize("-fcaller-saves") #pragma GCC optimize("-fcrossjumping") #pragma GCC optimize("-fthread-jumps") #pragma GCC optimize("-funroll-loops") #pragma GCC optimize("-fwhole-program") #pragma GCC optimize("-freorder-blocks") #pragma GCC optimize("-fschedule-insns") #pragma GCC optimize("inline-functions") #pragma GCC optimize("-ftree-tail-merge") #pragma GCC optimize("-fschedule-insns2") #pragma GCC optimize("-fstrict-aliasing") #pragma GCC optimize("-fstrict-overflow") #pragma GCC optimize("-falign-functions") #pragma GCC optimize("-fcse-skip-blocks") #pragma GCC optimize("-fcse-follow-jumps") #pragma GCC optimize("-fsched-interblock") #pragma GCC optimize("-fpartial-inlining") #pragma GCC optimize("no-stack-protector") #pragma GCC optimize("-freorder-functions") #pragma GCC optimize("-findirect-inlining") #pragma GCC optimize("-frerun-cse-after-loop") #pragma GCC optimize("inline-small-functions") #pragma GCC optimize("-finline-small-functions") #pragma GCC optimize("-ftree-switch-conversion") #pragma GCC optimize("-foptimize-sibling-calls") #pragma GCC optimize("-fexpensive-optimizations") #pragma GCC optimize("-funsafe-loop-optimizations") #pragma GCC optimize("inline-functions-called-once") #pragma GCC optimize("-fdelete-null-pointer-checks") #define inc(i,a,b) for(register int i=a;i<=b;i++) using namespace std; int head[200010],cnt; class littlestar{ public: int to; int nxt; int w; void add(int u,int v,int gg){ to=v; nxt=head[u]; head[u]=cnt; w=gg; } }star[2000010]; int n; long long val[100010]; int f[100010],top[100010],seg[100010],dep[100010],size[100010],rev[100010],son[100010]; long long b[100010]; void dfs1(int u,int fa) { dep[u]=dep[fa]+1; f[u]=fa; size[u]=1; for(int i=head[u];i;i=star[i].nxt){ int v=star[i].to; if(v==fa) continue; dfs1(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]){ son[u]=v; } } } void dfs2(int u,int fa) { if(son[u]){ seg[son[u]]=++seg[0]; rev[seg[0]]=son[u]; top[son[u]]=top[u]; dfs2(son[u],u); } for(int i=head[u];i;i=star[i].nxt){ int v=star[i].to; if(v==fa) continue; if(!top[v]){ seg[v]=++seg[0]; rev[seg[0]]=v; top[v]=v; dfs2(v,u); } } } void build() { seg[0]=seg[1]=rev[1]=top[1]=1; dfs1(1,0); dfs2(1,0); inc(i,1,n){ b[i]=val[rev[i]]; } } void dfs(int u,int fa) { for(register int i=head[u];i;i=star[i].nxt){ int v=star[i].to; if(v==fa) continue; val[v]=val[u]+star[i].w; dfs(v,u); } } int num; int belong[100010],l[100010],r[100010],block; long long gg[100010]; long long sum[100010]; void build2() { block=sqrt(n); num=n/block; if(n%block) ++num; inc(i,1,n){ gg[i]=b[i]; belong[i]=((i-1)/block)+1; } inc(i,1,num){ l[i]=block*(i-1)+1; r[i]=block*i; } r[num]=n; inc(i,1,num){ sort(gg+l[i],gg+1+r[i]); } inc(i,1,n) sum[i]=sum[i-1]+gg[i]; } long long ans; inline void query(register int x,register int y,long long goal) { if(belong[x]==belong[y]){ for(int j=x;j<=y;j++){ if(b[j]-b[x]>=goal) ans+=(b[j]-b[x]); } return; } for(register int i=x;i<=r[belong[x]];i++){ if(b[i]-b[x]>=goal) ans+=(b[i]-b[x]); } for(register int i=l[belong[y]];i<=y;i++){ if(b[i]-b[x]>=goal) ans+=(b[i]-b[x]); } for(register int i=belong[x]+1;i<=belong[y]-1;i++){ register int L=l[i],R=r[i],mid; while(L<R){ mid=(L+R)/2; if(gg[mid]-b[x]>=goal){ R=mid; } else{ L=mid+1; } } if(L==r[i]){ if(gg[L]-b[x]>=goal){ ans+=gg[L]-b[x]; } continue; } ans+=(sum[r[i]]-sum[L-1]-b[x]*(r[i]-L+1)); } } template<class nT> inline void read(nT& x) { char c; while(c=getchar(),!isdigit(c)); x=c^48; while(c=getchar(),isdigit(c)) x=x*10+c-48; } int main() { read(n); inc(i,2,n){ int u,w; scanf("%d%d",&u,&w); star[++cnt].add(u,i,w); } dfs(1,0); build(); build2(); int q;read(q); inc(i,1,q){ ans=0; long long x,goal; read(x); read(goal); query(seg[x],seg[x]+size[x]-1,goal); printf("%lld ",ans); } } /* 3 1 2 1 3 2 1 3 1 2 6 1 2 1 2 3 3 3 4 2 5 2 3 2 7 3 1 1 2 3 1 4 2 4 1 4 2 5 */