题目:
题解:
确实是很简单的题目(裸题啊)
在这里讨论一下关于calc的写法
写法1
for (int i=1;i<=m;i++)
{
int l=1,r=num,p=r;
while (l<r)
{
while (p>l && deep[p]>=deep[r]) p--;
p=max(p,l);
if (deep[l]+deep[r]==q[i])
{
ans[i]+=(vv)*(r-p); l++;
}
else
{
if (deep[l]+deep[r]>q[i]) r=p;else l++;
}
}
}
缺点1:不能统计上q[i]为0的时候,也就是无法单独选一个节点,但这个好办,特判一下就行了
缺点2:当有0权边时不能统计无关于长度的量
这一种写法用在了采药人的路径 这道题,在相同的量很多的情况下不用一个一个加下去,而是固定相同的区间,每次相同的直接加入,是比较好的做法
对于缺点2,“无关于长度的量”指的是Race,这里面统计的是深度,需要进行r的缩小,所以不能使用这种方法
但是在统计有关于长度的量的时候是最快的方法!
写法2
for (int i=1;i<=m;i++)
{
int l=1,r=num;
for (;l<r;l++)
{
while (l<r && deep[l]+deep[r]>q[i]) r--;
for (int j=r;l<j && deep[l]+deep[j]==q[i];j--) ans[i]+=vv;
}
}
这种写法同样不能统计上q[i]为0的时候,特判++;
可以使用,在本题上跑了652ms(?),却不清楚为什么跑的快
相比于上一个有优势在于r是-1-1-1的
写法3
for (int i=1;i<=m;i++)
{
int l=1,r=num;
for (;l<=r;l++)//这个等号不能省啊
{
while (l<r && deep[l]+deep[r]>q[i]) r--;
for (int j=r;deep[l]+deep[j]==q[i];j--) ans[i]+=vv;
}
}
相当于把重合的部分加了两遍,但是减的时候也是两遍,所以不会出错
而且q[i]为0的时候已经包含进去了!但尽量不要使用,毕竟慢啊。。。