2 条题解

  • 0
    @ 2026-5-28 22:13:41

    本题是 USACO25OPEN 银组实现难度略大的题,由于这只属于银组知识范围,所以在此我当然不会用什么高级数据结构或算法,仅仅是一个朴素的的预处理即可。

    根据题意,本题等效于给定一棵树和 MM 个查询,求满足指定条件的到根结点路径的最大边权和。由于本题询问量比较大,我们有两个方向:一个是带 log\log 查询,还有一个是预处理。注意到本题 ci10c_i \le 10,这透露给我们信息:可以预处理这 1111 种勇气值情况,再由二分技能水平找到符合条件的最大乐趣值。

    接下来考虑具体代码实现。我们可以由终点倒推,维护到每个出发点的前 1111 大的难度值和总乐趣值。接下来,对于每种勇气值,我们分别对这些该勇气值加 11 大的难度值及乐趣值构成的结构体进行排序。(该勇气值加 11 大的难度值为临界情况,依此排序)接下来我们再遍历排序后的结构体数组,维护 [1,i][1,i] 上的乐趣最大值。接下来,对于每个查询,我们先对勇气值对号入座,再二分在排序后结构体数组中的定位,输出预处理出来的乐趣最大值即可。

    时间复杂度 O(cNlogN+MlogN)O(c⋅N\log N+M\log N)c=11c= 11,表示 cic_i 值域大小)。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,p[100010],k;//一次性
    long long e[100010],d[100010],_max[12][100010],ans[12][100010];
    struct Node{
     long long e,max_[12];
     bool operator<(const Node& x)
     {return max_[k]<x.max_[k];
     }
    }a[100010];
    long long max_[12][100010];
    int main()
    {cin>>n;
     for(int i=2;i<=n;i++)
     {cin>>p[i]>>d[i]>>e[i];
      e[i]+=e[p[i]];
      a[i].e=e[i];
      for(int j=1;j<=11;j++)
      _max[j][i]=_max[j][p[i]];
      for(int j=1;j<=11;j++)
      {if(d[i]>_max[j][i])
       swap(d[i],_max[j][i]);
       a[i].max_[j]=_max[j][i];
      }
     }
     for(k=1;k<=11;k++)
     {sort(a+1,a+1+n);
      for(int i=2;i<=n;i++)
      {ans[k][i]=max(ans[k][i-1],a[i].e);
       max_[k][i]=a[i].max_[k];
      }
     }
     int m;cin>>m;
     while(m--)
     {int s,c;
      cin>>s>>c;
      c++;
      int id=upper_bound(max_[c]+1,max_[c]+n+1,s)-max_[c]-1;
      cout<<ans[c][id]<<'\n';
     }
    }
    
    • 0
      @ 2025-12-12 19:16:53
      #include<bits/stdc++.h>
      using namespace std;
      #define int long long
      const int N=1e5+10;
      int fa[N],d[N],e[N],ans[N],mx[15][N],f[15][N],nw;
      struct node{int id,f[15],siz;node(){memset(f,-1,sizeof(f));}}a[N];
      bool cmp(node n1,node n2){return n1.f[nw]<n2.f[nw];} 
      struct qnode{int c,s;}q[N];
      signed main()
      {
      	int n;cin>>n;
      	for(int i=2;i<=n;i++)cin>>fa[i]>>d[i]>>e[i];
      	for(int i=1;i<=n;i++)a[i].id=i;
      	for(int i=0;i<=10;i++)a[1].f[i]=0;
      	for(int i=2;i<=n;i++)
      	{
      		a[i].siz=a[fa[i]].siz+e[i];
      		for(int j=10;j>=0;j--)
      		{
      			if(a[fa[i]].f[j]<d[i])a[i].f[j+1]=a[fa[i]].f[j];
      			else a[i].f[j]=a[fa[i]].f[j];
      		}
      		for(int j=0;j<=10;j++)if(a[i].f[j]==-1&&a[fa[i]].f[j]!=-1)a[i].f[j]=d[i];
      	}
      	
      	for(int i=0;i<=10;i++)
      	{
      		nw=i;sort(a+1,a+n+1,cmp);
      		for(int j=1;j<=n;j++)f[i][j]=a[j].f[i];
      		for(int j=1;j<=n;j++)mx[i][j]=max(mx[i][j-1],a[j].siz);
      	}
      	int m;cin>>m;
      	for(int i=1;i<=m;i++)
      	{
      		int x,y;cin>>x>>y;
      		int ans=upper_bound(f[y]+1,f[y]+n+1,x)-f[y]-1;
      		cout<<mx[y][ans]<<'\n';
      	}
      	return 0;
      }
      • 1

      信息

      ID
      1564
      时间
      2000ms
      内存
      256MiB
      难度
      5
      标签
      递交数
      34
      已通过
      16
      上传者