zoukankan      html  css  js  c++  java
  • 【LOJ】 #2013. 「SCOI2016」幸运数字

    题解

    最大异或和,明显是个线性基
    然而还有那么多路径……那就树分治,反正点数看起来很少,就是为了让人乘上一个60的常数嘛
    把一个树的点分树记录下来,然后看看询问的两个点彼此相同的最后一个父亲是谁,把这个询问挂在这个点上,计算就暴力搜索这棵树里每一个节点到重心的线性基就行了,最后再用60的常数把两个线性基合起来

    代码

    #include <bits/stdc++.h>
    //#define ivorysi
    #define MAXN 20005
    #define MAXQ 200005
    typedef long long int64;
    typedef unsigned int u32;
    using namespace std;
    struct node {
        int to,next;
    }edge[MAXN * 2];
    int head[MAXN],sumE,n,m;
    int64 val[MAXN];
    vector<int> aux[MAXN],qry[MAXN];
    bool vis[MAXN];
    int que[MAXN],qr,ql;
    int siz[MAXN],son[MAXN],fa[MAXN];
    int st[MAXQ],ed[MAXQ];
    int64 dp[MAXN][65],ans[MAXQ];
    void add(int u,int v) {
        edge[++sumE].to = v;
        edge[sumE].next = head[u];
        head[u] = sumE;
    }
    void addtwo(int u,int v) {
        add(u,v);add(v,u);
    }
    int calc_G(int u) {
        que[ql = qr = 1] = u;
        fa[u] = 0;
        while(ql <= qr) {
    	int now = que[ql++];
    	siz[now] = 1;son[now] = 0;
    	for(int i = head[now] ; i ; i = edge[i].next) {
    	    int v = edge[i].to;
    	    if(!vis[v] && fa[now] != v) {
    		que[++qr] = v;
    		fa[v] = now;
    	    }
    	}
        }
        int res = que[qr];
        for(int i = qr ; i >= 1 ; --i) {
    	int now = que[i];
    	siz[fa[now]] += siz[now];
    	if(siz[now] > son[fa[now]]) son[fa[now]] = siz[now];
    	if(qr - siz[now] > son[now]) son[now] = qr - siz[now];
    	if(son[now] < son[res]) res = now;
        }
        return res;
    }
    void dfs(int u) {
        int G = calc_G(u);
        vis[G] = 1;
        for(int i = 1 ; i <= qr ; ++i) aux[que[i]].push_back(G);
        for(int i = head[G] ; i ; i = edge[i].next) {
    	int v = edge[i].to;
    	if(!vis[v]) dfs(v);
        }
    }
    void Init() {
        scanf("%d%d",&n,&m);
        for(int i = 1 ; i <= n ; ++i) scanf("%lld",&val[i]);
        int u,v;
        for(int i = 1 ; i < n ; ++i) {
    	scanf("%d%d",&u,&v);
    	addtwo(u,v);
        }
        dfs(1);
        for(int i = 1 ; i <= m ; ++i) {
    	scanf("%d%d",&st[i],&ed[i]);
    	if(st[i] == ed[i]) ans[i] = val[st[i]];
        }
        for(int i = 1 ; i <= m ; ++i) {
    	if(st[i] == ed[i]) continue;
    	int s = min(aux[st[i]].size(),aux[ed[i]].size());
    	bool flag = false;
    	for(int j = 0 ; j < s ; ++j) {
    	    if(aux[st[i]][j] != aux[ed[i]][j]) {
    		qry[aux[st[i]][j - 1]].push_back(i);
    		flag = 1;
    		break;
    	    }
    	}
    	if(!flag) qry[aux[st[i]][s - 1]].push_back(i);
        }
    }
    void insert(int id,int64 v) {
        for(int j = 60 ; j >= 0 ; --j) {
    	if(v >> j & 1) {
    	    if(dp[id][j]) v ^= dp[id][j];
    	    else {
    		dp[id][j] = v;
    		for(int k = 60 ; k > j ; --k) {
    		    if(dp[id][k] >> j & 1) dp[id][k] ^= dp[id][j];
    		}
    		break;
    	    }
    	}
        }
    }
    void calc(int u) {
        que[ql = qr = 1] = u;
        fa[u] = 0;
        memset(dp[u],0,sizeof(dp[u]));
        while(ql <= qr) {
    	int now = que[ql++];
    	for(int i = head[now] ; i ; i = edge[i].next) {
    	    int v = edge[i].to;
    	    if(!vis[v] && fa[now] != v) {
    		fa[v] = now;
    		memcpy(dp[v],dp[now],sizeof(dp[now]));
    		insert(v,val[v]);
    		que[++qr] = v;
    	    }
    	}
        }
    }
    void Process(int u) {
        for(auto k : aux[u]) vis[u] = 1;
        calc(u);
        
        for(auto k : qry[u]) {
    	memset(dp[n + 1],0,sizeof(dp[n + 1]));
    	insert(n + 1,val[u]);
    	for(int i = 0 ; i <= 60 ; ++i) {
    	    if(dp[st[k]][i]) insert(n + 1,dp[st[k]][i]);
    	    if(dp[ed[k]][i]) insert(n + 1,dp[ed[k]][i]);
    	}
    	for(int i = 60 ; i >= 0 ; --i) {
    	    if(!dp[n + 1][i]) continue;
    	    if(!(ans[k] >> i & 1)) ans[k] ^= dp[n + 1][i];
    	}
        }
        for(auto k : aux[u]) vis[u] = 0;
    }
    void Solve() {
        memset(vis,0,sizeof(vis));
        for(int i = 1 ; i <= n ; ++i) {
    	if(qry[i].size() != 0) {
    	    Process(i);
    	}
        }
        for(int i = 1 ; i <= m ; ++i) {
    	printf("%lld
    ",ans[i]);
        }
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
    }
    
  • 相关阅读:
    Android EditText 文本框实现搜索和清空效果
    Android学习笔记之打钩显示输入的密码
    Mysql limit offset
    Android SDK更新以及ADT更新出现问题的解决办法
    Android Broadcast Receiver 使用入门
    立即执行函数
    JS 原型 & 继承
    JS 对象
    chrome extension overview
    JS 修改元素
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9155841.html
Copyright © 2011-2022 走看看