• 浅谈整除分块(复习)


    复习整除分块

    经典例子:

    求Σ(n/i),n<=1e14,()为向下取整

    考虑直接暴力肯定不行,但发现其中有很多数是一样的

    引进整除分块:

    右端点为n/(n/l):表示n/l的值n中有多少个

    左端点为上一个r+1

    复杂度为根号n

    code:

    inline void init (int ans=0) {
        for(int l=1,r,len;l<=n;l=r+1) {
            r=n/(n/l),len=r-l+1;
            ans+=len*(n/l);
        }
    }
    

    当然整除分块不仅仅只能处理这种形式

    它是一种思想,一种美妙的剪枝

    应用:

    例题一:

    https://www.luogu.org/problem/P3935

    给定两个数L,R(L<=R<=1e9),求[L,R]中每个元素的约数个数和

    分析:

    首先很明显一个前缀和,剩下的问题成了求[1,X]中每个元素的约数个数和

    暴力不行,就只有分别考虑每个约数出现的次数了

    考虑[1,X]中以i为倍数的有X/i个

    所以答案就成了Σn/i

    code by wzxbeliever:

    #include<bits/stdc++.h>
    #define ll long long
    #define il inline
    #define ri register int
    #define lowbit(x) x&(-x)
    using namespace std;
    const int mod=998244353; 
    ll l,r;
    il ll solve(ll x){
    	ll ans=0;
    	for(register ll i=1,j;i<=x;i=j+1){
    		j=x/(x/i);
    		ans+=(j-i+1)*(x/i)%mod;
    	}
    	return ans;
    }
    int main(){
    	scanf("%lld%lld",&l,&r);
    	printf("%lld
    ",(solve(r)-solve(l-1)+mod)%mod);
    	return 0;
    }
    
    

    插入一个复习块(和本题无关):

    例题二:

    https://www.luogu.org/problem/P2261

    分析:

    code:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    
    int main() {
        ll n,k;
        scanf("%lld%lld",&n,&k);
        ll ans=n*k;
        for(ll l=1,r;l<=n;l=r+1) {
            if(k/l) r=min(k/(k/l),n); 
            else r=n;
            ans-=(k/l)*(r-l+1)*(l+r)/2;
        }
        printf("%lld",ans);
        return 0;
    }
    

    例题三:

    分析:

    分别算出(Nmodi)和(Mmodj)

    再将两者相乘

    即为答案

    例题四:

    吐槽:

    心路历程:1.考虑每段的贡献,但是要处理每个K,不现实

    ​ 2.考虑先不看节点,再找到一些规律,做一些变换得答案,但是貌似没啥规律结论

    分析:

    同样发现有很多的K的值不同,但得出的答案是一样的

    考虑整除分块

    将询问离线成三个点的询问,每个询问都是形如求f(u,1,w)的值。

    考虑每条边的贡献,整除分块后每次相当于将子树内每个点的f(u,1,l)~f(u,1,r)都加上一个值。

    于是我们最后再 dfs 一遍,经过一条边的时候,将这条边的边权整除分块,并在树状数组的对应区间上 修改,退出的时候再将该边的影响去除。遍历到某个点查询的时候,直接查询树状数组某个点的值即 可

    code by std:

    #include <bits/stdc++.h>
    
    template <class T>
    inline void read(T &x)
    {
    	static char ch; 
    	while (!isdigit(ch = getchar())); 
    	x = ch - '0'; 
    	while (isdigit(ch = getchar()))
    		x = x * 10 + ch - '0'; 
    }
    
    template <class T>
    inline void putint(T x)
    {
    	static char buf[25], *tail = buf; 
    	if (!x)
    		putchar('0'); 
    	else
    	{
    		for (; x; x /= 10) *++tail = x % 10 + '0'; 
    		for (; tail != buf; --tail) putchar(*tail); 
    	}
    }
    
    typedef long long s64; 
    
    const int MaxNV = 1e5 + 5; 
    const int MaxNE = MaxNV << 1; 
    
    const int MaxLog = 18; 
    
    struct request
    {
    	int d, opt, pos; 
    	request(){}
    	request(int y, int z, int p):
    		d(y), opt(z), pos(p) {}
    }; 
    
    int n, m = 30000, Q; 
    s64 bit[MaxNV], ans[MaxNV]; 
    
    std::vector<int> add[MaxNV]; 
    std::vector<request> req[MaxNV]; 
    
    int ect, adj[MaxNV]; 
    int to[MaxNE], e_w[MaxNE], nxt[MaxNE]; 
    
    int dep[MaxNV]; 
    int anc[MaxNV][MaxLog + 1]; 
    
    #define trav(u) for (int e = adj[u], v, w; v = to[e], w = e_w[e], e; e = nxt[e])
    
    inline void addEdge(int u, int v, int w)
    {
    	nxt[++ect] = adj[u]; 
    	adj[u] = ect; 
    	e_w[ect] = w; 
    	to[ect] = v; 
    }
    
    inline void bit_modify(int x, int del)
    {
    	for (; x <= m; x += x & -x)
    		bit[x] += del; 
    }
    
    inline s64 bit_query(int x)
    {
    	s64 res = 0; 
    	for (; x; x ^= x & -x)
    		res += bit[x]; 
    	return res; 
    }
    
    inline int query_lca(int u, int v)
    {
    	if (dep[u] < dep[v])
    		std::swap(u, v); 
    	for (int i = 0, d = dep[u] - dep[v]; d; d >>= 1, ++i)
    		if (d & 1)
    			u = anc[u][i]; 
    	if (u == v)
    		return u; 
    
    	for (int i = MaxLog; i >= 0; --i)
    		if (anc[u][i] != anc[v][i])
    		{
    			u = anc[u][i]; 
    			v = anc[v][i]; 
    		}
    	return anc[u][0]; 
    }
    
    inline void dfs_init(int u)
    {
    	for (int i = 0; anc[u][i]; ++i)
    		anc[u][i + 1] = anc[anc[u][i]][i]; 
    	trav(u) if (v != anc[u][0])
    	{
    		anc[v][0] = u; 
    		dep[v] = dep[u] + 1; 
    		dfs_init(v); 
    	}
    }
    
    inline void modify(int x, int opt)
    {
    	int lst = 0, lst_del = 0; --x; 
    	for (int cur = 1; cur <= x; cur = lst + 1)
    	{				
    		lst = x / (x / cur); 
    		bit_modify(cur, +opt * (x / cur + 1) - lst_del); 
    		lst_del = opt * (x / cur + 1); 
    	}
    	bit_modify(x + 1, opt - lst_del); 
    }
    inline void dfs_answer(int u)
    {
    	int cnt_req = req[u].size(); 
    	for (int j = 0; j < cnt_req; ++j)
    	{
    		int d = req[u][j].d, opt = req[u][j].opt; 
    		ans[req[u][j].pos] += bit_query(d) * opt; 
    	}
    
    	trav(u) if (v != anc[u][0])
    	{
    		modify(w, +1); 
    		dfs_answer(v); 
    		modify(w, -1); 
    	}
    }
    
    
    int main()
    {
    	freopen("delivery.in", "r", stdin); 
    	freopen("delivery.out", "w", stdout); 
    	read(n), read(Q); 
    	for (int i = 1; i < n; ++i)
    	{
    		int u, v, w; 
    		read(u), read(v), read(w); 
    		addEdge(u, v, w), addEdge(v, u, w); 
        }
    	dfs_init(1); 
    	for (int i = 1; i <= Q; ++i)
    	{
    		int u, v, w, z; 
    		read(u), read(v), read(w); 
    		z = query_lca(u, v); 
    		ans[i] = 1; 
    		req[u].push_back(request(w, +1, i)); 
    		req[v].push_back(request(w, +1, i)); 
    		req[z].push_back(request(w, -2, i)); 
    	}
    	dfs_answer(1); 
    	for (int i = 1; i <= Q; ++i)
    		putint(ans[i]), putchar('
    '); 
    
    	return 0; 
    }
    

    其实也可以平衡规划

    这一个阙值K,小于k的暴力预处理,大于k的主席树

    code by hs:

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 100010
    #define maxm 210
    template<typename T>T read()
    {
    	T res=0;
    	int sym=1;
    	char cc=getchar();
    	while(!isdigit(cc)&&cc!='-')
    		cc=getchar();
    	if(cc=='-')sym=-1,cc=getchar();
    	while(!isdigit(cc))cc=getchar();
    	while(isdigit(cc))res=res*10+cc-'0',cc=getchar();
    	return sym*res;
    }
    template<typename T>void read(T &o)
    {
    	o=read<T>();
    }
    template<typename A,typename... B>void read(A& o,B&... Others)
    {
    	o=read<A>();
    	read(Others...);
    }
    struct Edge
    {
    	int v;
    	int w;
    	Edge *next;
    	Edge(int a=0,int b=0,Edge *c=NULL)
    	{
    		v=a;
    		w=b;
    		next=c;
    	}
    }*head[maxn];
    struct Node
    {
    	int v;
    	int l;
    	int r;
    }node[maxn*50];
    int n,m,mx,cnt,T[maxn],dep[maxn],vis[maxm],fa[maxn][19];
    long long tot[maxm][maxn];
    void insert(int &a,int b,int l,int r,int x)
    {
    	a=++cnt;
    	node[a]=node[b];
    	node[a].v+=1;
    	if(l==r)return ;
    	int mid=(l+r)>>1;
    	if(x<=mid)insert(node[a].l,node[b].l,l,mid,x);
    	else insert(node[a].r,node[b].r,mid+1,r,x);
    }
    int query(int a,int b,int c,int l,int r,int x,int y)
    {
    	if(l>=x&&r<=y)
    		return node[a].v+node[b].v-2*node[c].v;
    	int mid=(l+r)>>1,ans=0;
    	if(x<=mid)
    		ans+=query(node[a].l,node[b].l,node[c].l,l,mid,x,y);
    	if(y>mid)
    		ans+=query(node[a].r,node[b].r,node[c].r,mid+1,r,x,y);
    	return ans;
    }
    void dfs(int k)
    {
    	dep[k]=dep[fa[k][0]]+1;
    	for(int i=1;i<=18;i++)
    		fa[k][i]=fa[fa[k][i-1]][i-1];
    	for(Edge *i=head[k];i!=NULL;i=i->next)
    	{
    		if(i->v==fa[k][0])
    			continue;
    		fa[i->v][0]=k;
    		insert(T[i->v],T[k],1,mx,i->w);
    		dfs(i->v);
    	}
    }
    void dfs2(int k,int t)
    {
    	for(Edge *i=head[k];i!=NULL;i=i->next)
    	{
    		if(i->v==fa[k][0])
    			continue;
    		tot[t][i->v]=tot[t][k]+(i->w-1)/t;
    		dfs2(i->v,t);
    	}
    }
    int lca(int x,int y)
    {
    	if(dep[x]<dep[y])
    		swap(x,y);
    	int d=dep[x]-dep[y];
    	for(int i=0;i<=18;i++)
    		if(d&(1<<i))
    			x=fa[x][i];
    	if(x==y)return x;
    	for(int i=18;i>=0;i--)
    		if(fa[x][i]!=fa[y][i])
    			x=fa[x][i],y=fa[y][i];
    	return fa[x][0];
    }
    int main()
    {
    	freopen("delivery.in","r",stdin);
    	freopen("delivery.out","w",stdout);
    	read(n,m);
    	for(int i=1;i<n;i++)
    	{
    		int x,y,z;
    		read(x,y,z);
    		mx=max(mx,z);
    		head[x]=new Edge(y,z,head[x]);
    		head[y]=new Edge(x,z,head[y]);
    	}
    	dfs(1);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,z;
    		read(x,y,z);
    		if(x==y)
    		{
    			puts("1");
    			continue;
    		}
    		int l=lca(x,y);
    		if(z<=200)
    		{
    			if(!vis[z])
    			{
    				dfs2(1,z);
    				vis[z]=true;
    			}
    			printf("%lld
    ",dep[x]+dep[y]-dep[l]-dep[fa[l][0]]+
    			tot[z][x]+tot[z][y]-tot[z][l]*2);
    			continue;
    		}
    		int ans=0;
    		for(int j=2;(j-1)*z+1<=mx;j++)
    		{
    			ans+=(j-1)*
    			query(T[x],T[y],T[l],1,mx,(j-1)*z+1,min(mx,j*z));
    		}
    		printf("%d
    ",ans+dep[x]+dep[y]-dep[l]-dep[fa[l][0]]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    数据库编程总结
    Excel文件操作方式比较
    大数据导入Excel
    导出Excel
    duilib库分析: 消息流程分析
    ucosII移植
    Log Parser Studio 分析 IIS 日志
    google 搜索关键字技巧
    未知的反物质世界的瞎想
    Scratch 简单的小游戏 --- 碰碰球
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11789027.html
Copyright © 2020-2023  润新知