zoukankan      html  css  js  c++  java
  • 不优雅的暴力——树分块

    我没想到省选 day2 宝石还可以用分块,话说当时我旁边的哥们就打了一个树分块……


    分块是个极不优美的做法,难写的离谱……(当然莫队系列除外

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

    本题强制在线。所以莫队被废了

    看到题目让求路径颜色数,考虑复杂度比较高的分块做法(话说我一开始想的是树上主席树

    树分块有很多分块方式

    跟据罗剑桥的国家集训队论文,我算是勉强掌握了一种。

    在树上撒(sqrt n)个关键点,要求对于每个非关键点,它的(1-sqrt n)级祖先中,必定存在至少一个关键点。

    容易知道每存在一个关键点能保证最少存在(sqrt n)个非关键点,那么全局最多有(sqrt n)个关键点

    而且若是沿着一个关键点向上跳,则最多跳大概(Theta(sqrt n))就会达到最靠近根节点的关键点。

    首先花费(O(nsqrt n))预处理所有关键点,然后花费(O(frac{n^2sqrt n}{w}))预处理任意两个关键点之间的颜色(用bitset

    考虑询问u,v两个点,先求出lca,然后求出离他们最近的关键点。之后关键点之间的颜色数直接调用预处理,关键点与u和v之间的颜色直接暴力即可

    总复杂度(O(frac{qnsqrt n}{w}))

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define INF 1<<30
    #define pb push_back
    %:define ill unsigned long long 
    %:define lowbit(x) (x&(-x))
    %:define Int unsigned int 
    
    const int np = 4e4 + 5;
    
    template<typename _T>
    inline void read(_T &x)
    {
    	x = 0;int f= 1;char s = getchar();
    	while(s<'0'||s>'9'){f=1;if(s=='-')f=-1;s=getchar();}
    	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
    	x*=f;
    }
    
    int head[np] , nxt[np * 2] , ver[np * 2];
    int tit;
    
    inline void add(int x,int y)
    {
    	ver[++tit] = y;
    	nxt[tit] = head[x];
    	head[x] = tit;
    }
    int dep[np];
    int val[np];
    int pos[np];
    int b[np];
    int key[np],fkey[np];
    int fa[np],son[np],siz[np];
    bitset<np> bit[59][59];
    int Top[np];
    
    inline bool cmp(int a,int b)
    {
    	return dep[a] > dep[b];
    }
    
    
    inline void dfs_key(int x,int ff)
    {
    	dep[x] = dep[ff] + 1;
    	fa[x] = ff;
    	siz[x] = 1;
    	for(int i=head[x],v;i;i=nxt[i])
    	{
    		v =ver[i];
    		if(v == ff) continue;
    		dfs_key(v,x);
    		siz[x] += siz[v];
    		if(siz[v] > siz[son[x]]) son[x] =v;
    	}
    }
    
    inline void dfs_pf(int x,int anc,int k_)
    {
    	if(key[x] && k_ != x) fkey[x] = k_,k_ = x;
    	Top[x] = anc;
    	
    	if(son[x]) dfs_pf(son[x] , anc,k_);
    	for(int i=head[x],v;i;i=nxt[i])
    	{
    		v = ver[i];
    		if(v == fa[x] || v == son[x]) continue;
    		dfs_pf(v,v,k_); 
    	}
    }
    
    inline int LCA(int x,int y)
    {
    	int fx = Top[x] ,fy = Top[y];
    	while(fx != fy)
    	{
    		if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
    		x = fa[fx];
    		fx = Top[x];
    	}
    	return dep[x] < dep[y]?x:y;
    }
    
    bitset<np> bi;
    inline void dfs_(int x,int k_,int ff)
    {
    	int posb = bi[val[x]];
    	bi[val[x]] = 1;
    	if(key[x]) 
    	{
    		if(key[x] >= k_)bit[k_][key[x]] = bit[key[x]][k_] = bi;
    	}
    	for(int i=head[x],v;i;i=nxt[i])
    	{
    		v =ver[i];
    		if(v == ff) continue;
    		dfs_(v,k_,x);
    	}
    	if(!posb) bi[val[x]] = 0;
    }
    
    inline int debug()
    {
    	return 1;
    }
    
    int T;
    int n,m;
    int key_[np];
    signed main()
    {
    //	cout<<(4e4 /700);// * (4e4/600) * 4e4/1024/1024;
    //	freopen("foo.in","r",stdin);
    //	freopen("my.out","w",stdout);
    //	freopen("data.in","r",stdin);
    //	freopen("my.out","w",stdout);
    	read(n);
    	read(m);
    //	T = sqrt(n);
    	T = 700;
    	for(int i=1;i<=n;i++) read(val[i]);
    	memcpy(b +1,val +1 ,sizeof(val));
    	sort(b + 1,b + 1 +n);
    	int *st = b +1 ;
    	int *ed = unique(b + 1,b +1 +n);
    	for(int i=1;i<=n;i++) val[pos[i] = i] = lower_bound(st,ed,val[i])-b;
    	for(int i=1,x,y;i<=n - 1;i++)
    	{
    		read(x);
    		read(y);
    		add(x,y);
    		add(y,x);
    	}
    	
    	dfs_key(1,0);
    	
    	sort(pos + 1,pos + 1 + n,cmp);
    //	for(int i=1;i<=n;i++) cout<<pos[i]<<" ";
    	
    //	cout<<'
    ';
    	for(int i=1;i<=n;i++)
    	{
    		int x = fa[pos[i]];
    		if(!x) continue;
    		int g=x;
    		for(int j=1;j<=T;j++)
    		{
    			if(key[x]) break;
    			if(!fa[x]) {
    				key[x] = 1;
    				break;
    			}
    			g =x;
    			x = fa[x];
    		}
    		if(key[x]) continue;
    		key[g] = 1;
    	}
    	
    	int top =0 ;
    	for(int i=1;i<=n;i++) if(key[i]) key_[++top] = i;
    	
    	if(!key[1]) key[1] = 1,key_[++top] = 1;
    	
    	for(int i=1;i<=top;i++)
    	{
    		key[key_[i]] = i;
    	}
    //	cout<<"*";
    	for(int i=1;i<=top;i++)
    	dfs_(key_[i],i,0) , bi.reset();
    //	return 0;
    	dfs_pf(1,1,1);
    	
    	int u,v,la =0 ;
    	
    //	for(int i=1;i<=top;i++) cout<<key_[i]<<" "<<key[key_[i]]<<'
    ';
    //	cout<<'
    ';
    //	for(int i=1;i<=top;i++)
    //	{
    //		for(int j=1;j<=top;j++)
    //		{
    //			int opi = bit[i][j].count();
    ////			cout<<i<<" "<<j<<" "<<opi<<'
    ';
    //		}
    //	}
    //	return 0;
    	bi.reset();
    	int h = 1;
    	while(m--)
    	{
    //		if(h == 2944) debug();
    		read(u);
    		read(v);
    //		read(la);
    //		int num = bi.count(); 
    		u = u ^ la;
    		int lca = LCA(u,v);
    		
    		int u_ = u,v_ = v;
    		while(!key[u_] && u_ != lca) bi[val[u_]] = 1,u_ = fa[u_];
    		while(!key[v_] && v_ != lca) bi[val[v_]] = 1,v_ = fa[v_];
    		
    		if(u_ != lca)
    		{
    			int cu = u_;
    			while(dep[fkey[u_]] > dep[lca]) u_ = fkey[u_];/*if(fkey[u_] == u_) break;*/ 
    			bi |= bit[key[u_]][key[cu]];
    			
    			while(u_ != lca) bi[val[u_]] = 1,u_ = fa[u_];
    		}
    		
    		if(v_ != lca)
    		{
    			int cv = v_;
    			while(dep[fkey[v_]] > dep[lca])  v_ = fkey[v_];/*if(fkey[v_] == v_) break;*/
    			bi |= bit[key[v_]][key[cv]];
    			while(v_ != lca) bi[val[v_]] = 1,v_ = fa[v_];			
    		}
    		bi[val[lca]] = 1;
    		u = bi.count();
    		printf("%d
    ",u);
    //		cout<<u<<'
    ';
    		bi.reset();
    		la = u;
    		h++;
    	}
    	
    	return 0;
    }
    
    
  • 相关阅读:
    HTML中设置在浏览器中固定位置fixed定位
    [简短问答]C-Lodop中一些测试用的地址
    LODOP打印超文本字符串拼接2 单选选择css样式表格
    HTML布局排版之制作个人网站的文章列表
    LODOP打印超文本字符串拼接1 固定表格填充数值
    HTML用table布局排版 padding清零
    [简短问答]LODOP套打问题及相关
    [简短问答]LODOP打印不清晰
    Unity3D深入浅出 -组件与节点之间的调用关系
    Unity3D深入浅出 -创造 物理材质(Physics Materials)
  • 原文地址:https://www.cnblogs.com/-Iris-/p/15350265.html
Copyright © 2011-2022 走看看