[[https://ac.nowcoder.com/acm/contest/6181|比赛链接]]
====== 题解 ======
===== A. Island Travels =====
===题解===
$\text{bfs}$ 求一下连通块,再 $\text{bfs}$ 求一下最短路,最后一个状压 $\text{dp}$ 就好了。
比赛的时候把最后的 $\text{dp}$ 当成 $\text{TSP}$ 问题了,但其实可以走重复的路,不然会漏解。
于是补了个 $\text{Floyd}$ 算法,就 $\text{AC}$ 了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
===== B. Cow Lineup =====
=== 题解 ===
直接取尺法就好了,但比赛的时候写麻烦了,还写了个线段树维护答案,其实不需要。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
===== I. Running Away From the Barn =====
=== 题解 ===
这题思路还挺多的。有跑树上差分 $+$ 倍增的;还有按 $\text{depth}$ 降序询问,然后权值线段树/树状数组维护答案的;还有左偏树的。
比赛时没想到调整询问顺序,直接写了个主席树 $+$ 权值线段树,感觉又写麻烦了。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=200005;
int n,id[N],r[N],now,ans[N];
pair a[N];
struct BIT
{
int tree[N];
void modify(int x,int val)
{
for(;x<=n;x+=x&-x)
tree[x]+=val;
}
int query(int x)
{
int ans=0;
for(;x;x-=x&-x)
ans+=tree[x];
return ans;
}
}T;
//树状数组模板
vector> mat[N];
void dfs(int k)
{
id[k]=++now;
//dfs序
for(auto e:mat[k])
{
a[e.first]=make_pair(a[k].first+e.second,e.first);
dfs(e.first);
}
r[k]=now;
//结束时间戳
}
int main()
{
long long l;
cin>>n>>l;
for(int i=2;i<=n;i++)
{
int p;
long long w;
cin>>p>>w;
mat[p].push_back(make_pair(i,w));
}
a[1]=make_pair(0ll,1);
dfs(1);
sort(a+1,a+n+1);
int j=n;
for(int i=n;i;i--)
{
for(;a[j].first-a[i].first>l;j--)
T.modify(id[a[j].second],-1);
//删除超过距离超过L的点
T.modify(id[a[i].second],1);
//插入当前点
ans[a[i].second]=T.query(r[a[i].second])-T.query(id[a[i].second]-1);
//统计子树答案
}
for(int i=1;i<=n;i++)
cout<
===== J. First! =====
=== 题解 ===
$\text{Trie}$ 建树,然后询问每个单词结点,如果他是某个单词结点的子结点,一定不合法。
沿路把 $\text{Trie}$ 的其他分支代表的字母向该路径代表字母连单向边,最后跑一下 $26$ 个字母的拓扑,看看合不合法。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include