zoukankan      html  css  js  c++  java
  • 342E. Xenia and Tree(sqrt-optimization+多源点BFS+倍增LCA)

    给出一棵树,一开始1号点是红色的,有2种操作:

    (1)把一个节点改成红色

    (2)每次询问一个红色节点,输出和它最接近的红色节点

    一个全新的套路:对询问分块+多源(BFS)

    用一个(Vector)保存当前还未被修改的红色节点

    将修改操作分块后,对每一块的操作先全部修改一遍,然后多源(BFS)更新每个蓝色节点和距离它最近红色节点的距离。

    然后对每个询问,先确定它距离已经修改的红色节点的最近距离,然后枚举还没修改的红色节点,用倍增(LCA)查询距离并更新之前保存的最近距离。

    因为分块的存在,可以保证(Vector)的大小始终是(sqrt n)

    总体时间复杂度(nsqrt nlogn)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+100;
    int n,m;
    vector<int> g[maxn];
    int is[maxn];//表示是否是红色节点
    int h[maxn],father[30][maxn];
    int d[maxn];//表示距离当前最近红色节点的距离
    vector<int> v;//表示还没有被染色的红色节点
    void dfs (int x) {
    	for (int y:g[x]) {
    		if (y==father[0][x]) continue;
    		father[0][y]=x;
    		h[y]=h[x]+1;
    		dfs(y);
    	}
    }
    int lca (int x,int y) {
    	if (h[x]<h[y]) swap(x,y);
    	for (int i=20;i>=0;i--) if (h[x]-h[y]>>i) x=father[i][x];
    	if (x==y) return x;
    	for (int i=20;i>=0;i--) {
    		if (father[i][x]!=father[i][y]) {
    			x=father[i][x];
    			y=father[i][y];
    		}
    	}
    	return father[0][x];
    }
    int getDis (int x,int y) {
    	return h[x]+h[y]-2*h[lca(x,y)];
    }
    int vis[maxn];
    void bfs () {
    	queue<int> q;
    	for (int i=1;i<=n;i++) vis[i]=0;
    	for (int i=1;i<=n;i++) if (is[i]) q.push(i),vis[i]=1,d[i]=0;
    	while (q.size()) {
    		int x=q.front();
    		q.pop();
    		for (int y:g[x]) {
    			if (vis[y]) continue;
    			d[y]=d[x]+1;
    			vis[y]=1;
    			q.push(y);
    		}
    	}
    }
    int main () {
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<n;i++) {
    		int x,y;
    		scanf("%d%d",&x,&y);
    		g[x].push_back(y);
    		g[y].push_back(x);
    	}
    	is[1]=1;
    	dfs(1);
    	bfs();
    	for (int i=1;i<=20;i++) for (int j=1;j<=n;j++) father[i][j]=father[i-1][father[i-1][j]];
    	
    	int Size=pow(4.5*m*log(n)/log(2.0),1.0/3)+1;
    	
    	
    	for (int i=1;i<=m;i++) {
    		int x,y;
    		scanf("%d%d",&x,&y);
    		if (x==1) {
    			v.push_back(y);
    			int vs=v.size();
    			if (vs==Size) {
    				//一个块满
    				for (int j=0;j<v.size();j++) is[v[j]]=1;
    				bfs();
    				v.clear(); 
    			}
    		}
    		else {
    			int ans=d[y];
    			for (int j=0;j<v.size();j++) ans=min(ans,getDis(y,v[j]));
    			printf("%d
    ",ans);
    		}
    	}
    }
  • 相关阅读:
    【树形DP】ZJOI2008 骑士
    【博弈论】CF 1215D Ticket Game
    【状态压缩DP】HDU 4352 XHXJ'S LIS
    【纯水题】CF 833A The Meaningless Game
    【不知道怎么分类】NOIP2016 蚯蚓
    【状态压缩DP】SCOI2009 围豆豆
    操作系统总结
    概率问题总结
    C++虚函数原理
    一些baidu面经
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14371379.html
Copyright © 2011-2022 走看看