• [SCOI2016]幸运数字


    题目

    来写一个(3)(log)的垃圾做法

    其实非常显然就是倍增把这条路径处理一遍,之后维护出倍增数组的线性基,大力合并就好了

    线性基合并就是把一个线性基的所有元素都拿出来,一个一个插入到另外一个中去

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 20005
    #define re register
    #define LL long long
    inline LL read() {
    	LL x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt;}e[maxn<<1];
    int f[maxn][17];
    LL a[maxn],lb[maxn][17][66];
    int log_2[maxn],deep[maxn],head[maxn];
    int n,num,Q;
    inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
    void dfs(int x) {
    	for(re int i=head[x];i;i=e[i].nxt) 
    	if(!deep[e[i].v]) {
    		deep[e[i].v]=deep[x]+1;f[e[i].v][0]=x;
    		dfs(e[i].v);
    	}
    }
    inline void ins(LL x,int t,int b) {
    	for(re int j=61;j>=0;--j)
    	if(x>>j&1ll) {
    		if(!lb[t][b][j]) {lb[t][b][j]=x;return;}
    		x^=lb[t][b][j];
    	}
    }
    inline void merge(int x,int y,int c,int d) {
    	for(re int t=61;t>=0;--t) {
    		if(!lb[c][d][t]) continue;
    		ins(lb[c][d][t],x,y);
    	}
    }
    inline void solve(int x,int y) {
    	memset(lb[0][0],0,sizeof(lb[0][0]));
    	if(x==y) {ins(a[x],0,0);return;}
    	if(deep[x]<deep[y]) std::swap(x,y);
    	for(re int i=log_2[deep[x]];i>=0;--i) 
    	if(f[x][i]&&deep[f[x][i]]>=deep[y]) 
    		merge(0,0,x,i),x=f[x][i];
    	if(x==y) return;
    	for(re int i=log_2[deep[x]];i>=0;--i) 
    	if(f[x][i]!=f[y][i]) {
    		merge(0,0,x,i),merge(0,0,y,i);
    		x=f[x][i],y=f[y][i];
    	}
    	ins(a[x],0,0),ins(a[y],0,0);if(f[x][0])ins(a[f[x][0]],0,0);
    }
    int main()
    {
    	n=read(),Q=read();
    	for(re int i=1;i<=n;i++) a[i]=read();
    	int x,y;
    	for(re int i=1;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
    	deep[1]=1;dfs(1);
    	for(re int i=2;i<=n;i++) log_2[i]=log_2[i>>1]+1;
    	for(re int i=1;i<=n;i++) ins(a[i],i,0);
    	for(re int i=1;i<=n;i++) if(f[i][0]) ins(a[f[i][0]],i,0);
    	for(re int j=1;j<=log_2[n];j++)
    		for(re int i=1;i<=n;i++) {
    			if(!f[i][j-1]) continue;
    			f[i][j]=f[f[i][j-1]][j-1];
    			merge(i,j,i,j-1);merge(i,j,f[i][j-1],j-1);
    		}
    	while(Q--) {
    		x=read(),y=read();
    		solve(x,y);
    		LL ans=0;
    		for(re int i=61;i>=0;--i) if((ans^lb[0][0][i])>ans) ans^=lb[0][0][i];
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    69道Java Spring 面试&笔试题
    不少程序员都会遇到的三个问题
    Java中main方面面试题
    学生成绩表(对成绩的操作)
    Eclipse常用快捷键
    java 调用打印机 打印服务
    java 打开浏览器 url
    java 邮件发送 apache commons-email
    java 邮件收发 (只能输入英文,中文需要转码)
    jquery 画板折叠
  • 原文地址:https://www.cnblogs.com/asuldb/p/10389288.html
Copyright © 2020-2023  润新知