NOIP模拟赛 打铁的匠 题解

【问题描述】

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\n",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
 
*/

 

posted @ 2019-10-31 19:14  神之右大臣  阅读(459)  评论(0编辑  收藏  举报