【牛客网】【埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛】B—合约数【莫队做法】

题目链接:B—合约数

题意:一棵树,有n个节点,从1编号到n。根节点的编号为p。给出每个节点的val[i]值,定义f(i)为以编号i为根节点的子树中(包括根节点),所有val[j]是合数并且是val[i]的约数的节点个数。求所有f(i)的和。答案对1e9+7取模。

题解:学长说可以用set的启发式合并或者splay的启发式合并。emmm,我太菜了不会这些怎么写。我的做法是:预处理范围内的数字是否是合数,然后对1-10000的数字用vector数组存下各自的因数。然后用dfs序,将各子树变成一个区间问题,用莫队算法解决。n是20000,每个数字不超过10000,这样复杂度就是 20000*(200+约数的个数,没几十个)。

ac代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int val[20000+10];
int block;
int caz=0;
long long mod =1000000007;
int vis[20000+10];
int cishu[20000+10];
int num[20000+10];
int notprime[20000+10];
int prime[20000+10];
vector vt[10000+10];
int cnt=0;
struct Query
{
    int l,r,pos;
}query[20000+10];
bool cmp(Query a,Query b)
{
    if(a.l/block!=b.l/block){
        return a.l::iterator it=vt[val[query[1].pos]].begin();
        for(;it!=vt[val[query[1].pos]].end();++it){
            temp+=cishu[*it];
        }
        ans=(ans+temp*query[1].pos%mod)%mod;
        printf("%lld\n",ans);
        for(int i=2;i<=n;i++){
            if(query[i].l>L){
                while(query[i].l>L){
                    cishu[num[L]]--;
                    L++;
                }
            }
            else if(query[i].lR){
                while(query[i].r>R){
                    R++;
                    cishu[num[R]]++;
                }
            }
            else if(query[i].r

你可能感兴趣的:(莫队算法)