bzoj 3569 DZY Loves Chinese II 随机算法 树上倍增

Posted pkgunboat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3569 DZY Loves Chinese II 随机算法 树上倍增相关的知识,希望对你有一定的参考价值。

题意:给你一个n个点m条边的图,有若干组询问,每次询问会选择图中的一些边删除,删除之后问此图是否联通?询问之间相互独立。此题强制在线。

思路:首先对于这张图随便求一颗生成树,对于每一条非树边,随机一个权值。树边的权值为所有覆盖这条树边的非树边的权值异或和。覆盖是指这条边是个返祖边,并且一端在父节点方向,一端在子节点方向。这样,我们选出若干条边,看一下他们异或起来是不是0,如果是0,那么相当于把一条树边和它的所有子节点方向的返祖边全部断开,那么图就不连通了。

代码:

#include <bits/stdc++.h>
#define LL long long
#define pii pair<int, int>
using namespace std;
const int maxn = 100010;
const int maxm = 500010;
const LL mod = 1e18;
mt19937 Random(time(0));
LL get(void) 
	return 1ll * Random() * rand();

vector<pii> G[maxn], G1[maxn];
LL val[maxn];
int d[maxn], f[maxn][18], t;
bool v[maxn], v1[maxm];
struct edge 
	int u, v;
	LL w;
;
edge a[maxm];
void add(int x, int y, int id) 
	G[x].push_back(make_pair(y, id));
	G[y].push_back(make_pair(x, id));

void add1(int x, int y, int id) 
	G1[x].push_back(make_pair(y, id));
	G1[y].push_back(make_pair(x, id));

void dfs(int x) 
	v[x] = 1;
	for (auto y : G[x]) 
		if(v[y.first]) continue;
		dfs(y.first);
		add1(x, y.first, y.second);
		v1[y.second] = 1;
	


queue<int> q;
void bfs() 
	q.push(1);
	d[1] = 1;
	while(q.size()) 
		int x = q.front();
		q.pop();
		for (auto y : G1[x]) 
			if(d[y.first]) continue;
			d[y.first] = d[x] + 1;
			f[y.first][0] = x;
			for (int i = 1; i <= t; i++) 
				f[y.first][i] = f[f[y.first][i - 1]][i - 1];
			
			q.push(y.first);
		
	


int lca(int x, int y) 
	if(d[x] > d[y]) swap(d[x], d[y]);
	for (int i = t; i >= 0; i--) 
		if(d[f[y][i]] >= d[x]) y = f[y][i];
	
	if(x == y) return x;
	for (int i = t; i >= 0; i--) 
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	
	return f[x][0];
	

LL dfs1(int x, int fa) 
	for (auto y : G1[x]) 
		if(y.first == fa) continue;
		dfs1(y.first, x);
		a[y.second].w = val[y.first];
		val[x] ^= val[y.first];
	

struct L_B
    long long d[61],p[61];
    int cnt;
    void init()
        memset(d,0,sizeof(d));
        memset(p,0,sizeof(p));
        cnt=0;
    
    bool insert(long long val)
        for (int i=60;i>=0;i--)
            if (val&(1LL<<i))
            
                if (!d[i])
                
                    d[i]=val;
                    break;
                
                val^=d[i];
            
        return val>0;
    
    long long query_max() 
        long long ret=0;
        for (int i=60;i>=0;i--)
            if ((ret^d[i])>ret)
                ret^=d[i];
        return ret;
    
    long long query_min() 
        for (int i=0;i<=60;i++)
            if (d[i])
                return d[i];
        return 0;
    
    void rebuild() 
        for (int i=60;i>=0;i--)
            for (int j=i-1;j>=0;j--)
                if (d[i]&(1LL<<j))
                    d[i]^=d[j];
        for (int i=0;i<=60;i++)
            if (d[i])
                p[cnt++]=d[i];
    
    long long kthquery(long long k) 
        int ret=0;
        if (k>=(1LL<<cnt))
            return -1;
        for (int i=60;i>=0;i--)
            if (k&(1LL<<i))
                ret^=p[i];
        return ret;
    
;
int main() 
	int n, m, cnt = 0, x, y, num, T;
	srand(time(0));
	scanf("%d%d", &n, &m);
	t = (int)(log(n) / log(2)) + 1;
	for (int i = 1; i <= m; i++) 
		scanf("%d%d", &a[i].u, &a[i].v);
		add(a[i].u, a[i].v, i);
	
	dfs(1);
	bfs();
	for (int i = 1; i <= m; i++) 
		if(v1[i]) continue;
		a[i].w = get();
		int tmp = lca(a[i].u, a[i].v);
		val[a[i].u] ^= a[i].w;
		val[tmp] ^= a[i].w;
		val[a[i].v] ^= a[i].w;
		val[tmp] ^= a[i].w;
	
	dfs1(1, -1);
	scanf("%d", &T);
	while(T--) 
		scanf("%d", &num);
		bool flag = 1;
		L_B solve;
		solve.init();
		for (int i = 1; i <= num; i++) 
			scanf("%d", &x);
			x ^= cnt;
			flag = (flag & solve.insert(a[x].w));
		
		if(flag == 0) 
			printf("Disconnected\n");
		 else 
			printf("Connected\n");
			cnt++;
		
	
 

  

以上是关于bzoj 3569 DZY Loves Chinese II 随机算法 树上倍增的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3569: DZY Loves Chinese II

bzoj3569 DZY Loves Chinese II

BZOJ3569 DZY Loves Chinese II

bzoj3569 DZY Loves Chinese II

bzoj3569 DZY Loves Chinese II

BZOJ 3569 DZY Loves Chinese II