zoukankan      html  css  js  c++  java
  • 树分块小结

    其实就是一个简单的trick((color{black}{ exttt{F}}color{red}{ exttt{orever_Pursuit}}) :分块强行上树有什么意思)。网上我只找到了两道例题。

    P6177 Count on a tree II/【模板】树分块

    P3603 雪辉

    说句闲话:我因为一个傻逼错误第一题从9:00调到11:45吃饭,12:00THUPC初赛。于是我非常困地开始了比赛,罚了我们队200min而且0输出。希望队友原谅我吧/kel

    upd 2020.1.4,18:40:忽然发现树分块写假了,链底下挂一个菊花并且对着块长卡就没了,代码已经修改(但是能过lxl的数据还跑成最优解就离谱)。【数据删除】

    P6177 Count on a tree II/【模板】树分块

    直接放题吧。强制在线树上路径数颜色。

    我们考虑往树上撒关键点点。随机撒 (sqrt n) 个期望是对的,但是有确定性做法(Orz mrsrz):

    如果一个点往上 (S) 个点都没有关键点,那么这个点就标记成关键点。

    显然一个点标记之后至少 (S) 个点不会被标记,那么总点数是 (dfrac{n}{S}) 级别的。

    如果直接这样实现是 (O(nS)) 的,虽然没啥问题,可是其实是可以 (O(n)) 的。

    我们把这个东西转化成:对于一个点 (u) ,如果存在一条从 (u) 往下的路径,长度 (> S) ,那么 (u) 就是关键点。

    这样我们维护每一个点往下的最长非关键点路径长度即可。

    接下去我们维护任意两个关键点间的信息。比如这题可以直接用 bitset ,把颜色离散化后开到值域上。

    如果我们暴力把 (dfrac{n}{S}) 个点拿出来dfs一遍就是 (dfrac{n^2}{S} imes dfrac{n}{omega}) 的了。

    但是有 (O(dfrac{n^2}{S^2} imesdfrac{n}{omega}+dfrac{n^2}{S})) 的做法:

    对于每一个关键点记录它上方的关键点是什么,先 (O(S)) 跳出相邻关键点间的信息,然后暴力往上跳关键点,bitset 的话直接或起来就好了。

    总共不会超过 ((dfrac{n}{S})^2) 对点,所以复杂度就是上面那玩意。

    这些信息我们都预处理掉就可以快速处理询问了。

    设我们询问 (x,y) 间的颜色数, (lca)(x,y) 的最近公共祖先。

    那么可以把路径拆成 (6) 段:

    (x)(x) 上方第一个关键点 (x')(x')(lca) 下方最高在 (x o lca) 路径上最高的的关键点 (x'')(x'')(lca)
    (y)(y) 上方第一个关键点 (y')(y')(lca) 下方最高在 (y o lca) 路径上最高的的关键点 (y'')(y'')(lca)

    颜色全部或起来就好了。

    可以发现左右两边的 (4) 条都是 (O(S)) 的,中间两条是 (O(dfrac{n}{S})) ,而且大多都跑不满。

    这题完结了。

    不过值得一提,这东西的时空复杂度都有点鬼畜,这里不建议直接把 (S) 当成 (sqrt n) ,这个参数活动性很大。

    根据上面的分析,时间复杂度上限是 (O(dfrac{n^2}{S}+dfrac{n^3}{S^2omega}+dfrac{nm}{omega}+dfrac{nm}{S}+mS)),空间复杂度是 (O(dfrac{n^3}{S^2omega})),但是如果这棵树长得并不那么像链是严重不满的,这东西大概在序列上才会被卡满。

    可见这东西复杂度并不友善,各方面都要平衡到。所以这东西是不是没啥用啊

    (S) 线性增加,空间平方减少。所以空间一定要算过,块长一般尽量开小。因为空间复杂度决定了块长必然大于 (sqrt n) ,而块长在 (sqrt n) 的时候时间复杂度最优,所以尽量开小。

    一个显著的空间优化

    如果预处理bitset的时候合并这么写:bs[x][y]=bs[x][z]|bs[z][y] ,会MLE成傻子。

    但是这么写就没事:(bs[x][y]=bs[x][z])|=bs[z][y]

    因为上面那种写法会新开一个bitset,很费空间,申请空间也很费时间。

    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define mkp(x,y) make_pair(x,y)
    #define pb(x) push_back(x)
    #define sz(v) (int)v.size()
    typedef long long LL;
    typedef double db;
    template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
    template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
    #define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
    #define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f?x:-x;
    }
    const int N=40005;
    const int S=800;
    int n,m,lsh[N],len,a[N],lastans;
    int top[N],fa[N],dep[N],siz[N],son[N];
    int id[N],tot,mxd[N],up[N];
    bitset<N>bs[N/S+5][N/S+5];
    int hed[N],et;
    struct edge{int nx,to;}e[N<<1];
    void adde(int u,int v){e[++et].nx=hed[u],e[et].to=v,hed[u]=et;}
    void dfs1(int u,int ft){
    	siz[u]=1,mxd[u]=dep[u];
    	for(int i=hed[u];i;i=e[i].nx){
    		int v=e[i].to;if(v==ft)continue;
    		dep[v]=dep[u]+1,dfs1(v,u),siz[u]+=siz[v],fa[v]=u;
    		ckmax(mxd[u],mxd[v]);
    		if(siz[v]>siz[son[u]])son[u]=v;
    	}
    	if(u==1||mxd[u]-dep[u]>S)mxd[u]=dep[u],id[u]=++tot;
    }
    void dfs2(int u,int tp){
    	top[u]=tp;
    	if(son[u])dfs2(son[u],tp);
    	for(int i=hed[u];i;i=e[i].nx){
    		int v=e[i].to;if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    void dfs(int u,int ft,int lst){
    	if(id[u]){
    		up[u]=lst,bs[id[u]][id[u]].set(a[u]);
    		int now=u;
    		while(now!=fa[lst])bs[id[u]][id[lst]].set(a[now]),now=fa[now];
    		now=up[lst];
    		while(now)(bs[id[u]][id[now]]=bs[id[u]][id[lst]])|=bs[id[lst]][id[now]],now=up[now];
    	}
    	for(int i=hed[u];i;i=e[i].nx){
    		int v=e[i].to;if(v==ft)continue;
    		dfs(v,u,id[u]?u:lst);
    	}
    }
    int LCA(int x,int y){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]])x^=y^=x^=y;
    		x=fa[top[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    signed main(){
    	n=read(),m=read();
    	rep(i,1,n)a[i]=lsh[++len]=read();
    	sort(lsh+1,lsh+len+1),len=unique(lsh+1,lsh+len+1)-lsh-1;
    	rep(i,1,n)a[i]=lower_bound(lsh+1,lsh+len+1,a[i])-lsh;
    	rep(i,2,n){
    		int x=read(),y=read();
    		adde(x,y),adde(y,x);
    	}
    	dep[1]=1,dfs1(1,0),dfs2(1,1),dfs(1,0,0);
    	while(m--){
    		static bitset<N>ans;
    		int x=read()^lastans,y=read(),lca=LCA(x,y);
    		ans.reset(),ans.set(a[lca]);
    		while(!id[x]&&x!=lca)ans.set(a[x]),x=fa[x];
    		while(!id[y]&&y!=lca)ans.set(a[y]),y=fa[y];
    		if(x!=lca){
    			int now=x;
    			while(up[now]&&dep[up[now]]>dep[lca])now=up[now];
    			ans|=bs[id[x]][id[now]];
    			while(now!=lca)ans.set(a[now]),now=fa[now]; 
    		}
    		if(y!=lca){
    			int now=y;
    			while(up[now]&&dep[up[now]]>dep[lca])now=up[now];
    			ans|=bs[id[y]][id[now]];
    			while(now!=lca)ans.set(a[now]),now=fa[now];
    		}
    		printf("%d
    ",lastans=ans.count());
    	}
    }
    

    P3603 雪辉

    有了上一题,这题应该非常基础了。

    链上数颜色和上一题一样搞,链并就把bitset或起来。

    求mex手写一个bitset就好了

    //Orz cyn2006
    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    #define mkp(x,y) make_pair(x,y)
    #define pb(x) push_back(x)
    #define sz(v) (int)v.size()
    typedef long long LL;
    typedef double db;
    template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
    template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
    #define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
    #define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f?x:-x;
    }
    const int N=100005;
    const int M=30005;
    const int S=600;
    template<int N>struct Bitset{
    
    typedef unsigned long long ull;
    static const int O=(N-1)/64+1;
    static const ull ULL_MAX=18446744073709551615ull;
    ull a[O];
    Bitset(){memset(a,0,sizeof(a));}
    void reset(){memset(a,0,sizeof(a));}
    void set(int x){a[(x>>6)]|=1ull<<(x&63);}
    Bitset&operator |= (const Bitset&t){
    	for(int i=0;i<O;++i)a[i]|=t.a[i];
    	return *this;
    }
    Bitset operator | (const Bitset&t){
    	Bitset res;
    	for(int i=0;i<O;++i)res.a[i]=a[i]|t.a[i];
    	return res;
    }
    int count(){
    	int res=0;
    	for(int i=0;i<O;++i)res+=__builtin_popcountll(a[i]);
    	return res;
    }
    int mex(){
    	for(int i=0;i<O;++i)if(a[i]<ULL_MAX)
    		for(int j=0;j<64;++j)if(!(a[i]>>j&1ull))return (i<<6)|j;
    	return N+1;
    }
    
    };
    Bitset<M>bs[N/S+5][N/S+5];
    int n,m,f,lastans,a[N];
    int siz[N],fa[N],top[N],son[N],dep[N],mxd[N];
    int id[N],tot,up[N];
    int et,hed[N];
    struct edge{int nx,to;}e[N<<1]; 
    void adde(int u,int v){e[++et].nx=hed[u],e[et].to=v,hed[u]=et;}
    void dfs1(int u,int ft){
    	mxd[u]=dep[u],siz[u]=1;
    	for(int i=hed[u];i;i=e[i].nx){
    		int v=e[i].to;if(v==ft)continue;
    		dep[v]=dep[u]+1,dfs1(v,u);
    		fa[v]=u,siz[u]+=siz[v];
    		ckmax(mxd[u],mxd[v]);
    		if(siz[v]>siz[son[u]])son[u]=v;
    	}
    	if(u==1||mxd[u]-dep[u]>S)id[u]=++tot,mxd[u]=dep[u];
    }
    void dfs2(int u,int tp){
    	top[u]=tp;
    	if(son[u])dfs2(son[u],tp);
    	for(int i=hed[u];i;i=e[i].nx){
    		int v=e[i].to;
    		if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    void dfs(int u,int ft,int lst){
    	if(id[u]){
    		up[u]=lst,bs[id[u]][id[u]].set(a[u]);
    		if(lst){
    			int now=u;
    			while(now!=lst)bs[id[u]][id[lst]].set(a[now]),now=fa[now];
    			now=up[lst];
    			while(now)(bs[id[u]][id[now]]=bs[id[u]][id[lst]])|=bs[id[lst]][id[now]],now=up[now];
    		}
    	}
    	for(int i=hed[u];i;i=e[i].nx){
    		int v=e[i].to;if(v==ft)continue;
    		dfs(v,u,id[u]?u:lst);
    	}
    }
    int LCA(int x,int y){
    	while(top[x]!=top[y])dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
    	return dep[x]<dep[y]?x:y;
    }
    signed main(){
    	n=read(),m=read(),f=read();
    	rep(i,1,n)a[i]=read();
    	rep(i,2,n){
    		int x=read(),y=read();
    		adde(x,y),adde(y,x);
    	}
    	dep[1]=1,dfs1(1,0),dfs2(1,1),dfs(1,0,0);
    	while(m--){
    		int q=read(),mex,sum;
    		static Bitset<M>ans;
    		ans.reset();
    		rep(i,1,q){
    			int x=read(),y=read();
    			if(f)x^=lastans,y^=lastans;
    			int lca=LCA(x,y);
    			ans.set(a[lca]);
    			while(!id[x]&&x!=lca)ans.set(a[x]),x=fa[x];
    			while(!id[y]&&y!=lca)ans.set(a[y]),y=fa[y];
    			if(x!=lca){
    				int now=x;
    				while(dep[up[now]]>=dep[lca])now=up[now];
    				ans|=bs[id[x]][id[now]];
    				while(now!=lca)ans.set(a[now]),now=fa[now];
    			}
    			if(y!=lca){
    				int now=y;
    				while(dep[up[now]]>=dep[lca])now=up[now];
    				ans|=bs[id[y]][id[now]];
    				while(now!=lca)ans.set(a[now]),now=fa[now];
    			}
    		}
    		lastans=(sum=ans.count())+(mex=ans.mex()),printf("%d %d
    ",sum,mex); 
    	}
    }
    
  • 相关阅读:
    MVC学习中遇到问题
    静态类和单例模式区别
    类或方法名后加<>
    MVC5入门
    开发BI系统时的需求分析研究
    BI项目需求分析书-模板
    商业智能学习系统
    数据库设计三大范式[转]
    BW对应后台表[转]
    SQL优化方案
  • 原文地址:https://www.cnblogs.com/zzctommy/p/14127290.html
Copyright © 2011-2022 走看看