zoukankan      html  css  js  c++  java
  • BZOJ4568 [Scoi2016]幸运数字

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

    题目链接:BZOJ4568

    正解:线性基+链剖+线段树

    解题报告:

      考虑直接用线段树维护线性基,构出来之后,每次询问都只需要在树上跳就好了。

      线性基可以暴力合并,合并的复杂度是$O(log^2n)$。

      最后查询一遍合并得到的最终线性基就可以了。

    $UPD$:

      考虑树分治做法:我们把询问离线下来,然后每次分治的时候$dfs$求出重心到所有的点,路径上的线性基。

      接着就看一下所有的询问,如果询问的两个点分居不同子树中,那么直接回答询问就好了,时间复杂度:$O(60*nlogn+q*60*60)$,而且线性基里面加$break$还有各种优化之后,远远不到上界…

      当然如果强制在线的话,就可以用动态树分治的做法,保存下树的结构,存下重心到分治结构中每个点的线性基,回答就在分治结构树上走就好了。不过在线的这个做法空间复杂度是$O(60*nlogn)$的…

    贴一发简单暴力无脑的解法一的代码:

    //It is made by ljh2000
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #include <string>
    #include <complex>
    #include <bitset>
    using namespace std;
    typedef long long LL;
    typedef long double LB;
    typedef complex<double> C;
    const double pi = acos(-1);
    const int MAXN = 40011;
    const int MAXM = 400011;
    int n,m,ecnt,first[MAXN],to[MAXM],next[MAXM],top[MAXN],deep[MAXN],father[MAXN],size[MAXN],son[MAXN],id[MAXN],pre[MAXN],flag,ql,qr;
    LL val[MAXN],lin,ans;
    struct node{ LL s[62]; int dui[62],top; }a[MAXN*3],tmp;
    inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline LL getLL(){
        LL w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void dfs(int x,int fa){
    	size[x]=1;
    	for(int i=first[x];i;i=next[i]) {
    		int v=to[i]; if(v==fa) continue;
    		deep[v]=deep[x]+1; father[v]=x; dfs(v,x);
    		size[x]+=size[v]; if(size[v]>size[son[x]]) son[x]=v;
    	}
    }
    
    inline void dfs2(int x,int fa){
    	id[x]=++ecnt; pre[ecnt]=x;
    	if(son[x]) { top[son[x]]=top[x]; dfs2(son[x],x); }
    	for(int i=first[x];i;i=next[i]) {
    		int v=to[i]; if(v==fa || v==son[x]) continue;
    		top[v]=v; dfs2(v,x);
    	}
    }
    
    inline node merge(node q,node qq){
    	if(q.top>qq.top) swap(q,qq);
    	for(int i=1;i<=q.top;i++) {
    		lin=q.s[ q.dui[i] ];
    		for(int j=60;j>=0;j--) {
    			if(!( (lin>>j) &1 )) continue;
    			if(!qq.s[j]) { qq.dui[ ++qq.top ]=j/*!!!*/; qq.s[j]=lin; break; }
    			lin^=qq.s[j];
    		}
    	}
    	return qq;
    }
    
    inline void build(int root,int l,int r){
    	if(l==r) { 
    		for(int i=60;i>=0;i--) if(val[pre[l]]>>i) { a[root].s[i]=val[pre[l]]; a[root].dui[1]=i; break; }
    		a[root].top=1;
    		return ; 
    	}
    	int mid=(l+r)>>1; int lc=root<<1,rc=root<<1|1;
    	build(lc,l,mid); build(rc,mid+1,r);
    	a[root]=merge(a[lc],a[rc]);
    }
    
    inline void query(int root,int l,int r){
    	if(ql<=l && r<=qr) {
    		if(!flag) tmp=a[root],flag=1;
    		else tmp=merge(tmp,a[root]);
    		return ;
    	}
    	int mid=(l+r)>>1; int lc=root<<1,rc=root<<1|1;
    	if(ql<=mid) query(lc,l,mid); if(qr>mid) query(rc,mid+1,r);
    }
    
    inline void lca(int x,int y){
    	int f1=top[x],f2=top[y]; flag=0;
    	while(f1!=f2) {
    		if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y);
    		ql=id[f1]; qr=id[x]; 
    		query(1,1,n);
    		x=father[f1]; f1=top[x];
    	}
    	if(deep[x]<deep[y]) swap(x,y);
    	ql=id[y]; qr=id[x];
    	query(1,1,n);
    }
    
    inline void work(){
    	n=getint(); m=getint(); for(int i=1;i<=n;i++) val[i]=getLL(); int x,y;
    	for(int i=1;i<n;i++) {
    		x=getint(); y=getint();
    		link(x,y); link(y,x);
    	}
    	deep[1]=1; dfs(1,0);
    	ecnt=0; top[1]=1; dfs2(1,0);
    	build(1,1,n);
    	while(m--) {
    		x=getint(); y=getint();
    		lca(x,y);
    		ans=0;
    		for(int i=60;i>=0;i--) if(( ans^(tmp.s[i]) )>ans) ans^=tmp.s[i];
    		printf("%lld
    ",ans);
    	}
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("4568.in","r",stdin);
    	freopen("4568.out","w",stdout);
    #endif
        work();
        return 0;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    Codeforces1070 2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)总结
    Codeforces 633H Fibonacci-ish II【线段树】
    一些Fibonacci数列的神奇性质【数学】
    Codeforces 620E New Year Tree【线段树傻逼题】
    Codeforces 828C String Reconstruction【并查集巧妙运用】
    Codeforces 559C Gerald and Giant Chess【组合数学】【DP】
    Codeforces 311B Cats Transport【斜率优化DP】
    BZOJ2933 [Poi1999]地图【区间DP】
    BZOJ3688 折线统计【树状数组优化DP】
    BZOJ2131 免费的馅饼【线段树优化DP】
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6616505.html
Copyright © 2011-2022 走看看