[BZOJ1316]点分治关于定长问题的讨论

来源:互联网 发布:淘宝 产品对比 违规 编辑:程序博客网 时间:2024/06/10 02:47

题目:

我是超链接

题解:

确实是很简单的题目(裸题啊)
在这里讨论一下关于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的时候已经包含进去了!但尽量不要使用,毕竟慢啊。。。