BZOJ 4568 [Scoi2016]幸运数字 【倍增线性基

80 篇文章 0 订阅
6 篇文章 0 订阅

嗯今年的省选题……我才不是从省选颓到现在才把它写了呢哼唧

嗯……其实这题真的就是标准的模板套模板啊┑(°Д °)┍

倍增模板里套个线性基……都不难写【但是一般都用链剖写lca的我毫不犹豫写跪了倍增lca【助けて下さいQuQ

嗯……脑子是个好东西……感觉写了这道题智力--一定是我太辣鸡【望天

嗯对……调了好几天的原因啊 EXCITING

-LCA写挂了智力-=INF

-在线性基的merge那儿忘了开 long long【嗯没错就是一个不起眼的小地方哼,define int long long 拯救世界xxx

-哦……线性基的合并要剪枝……身为智障我毫不犹豫地……嗯……60*60的常数开满了……【学习常数优化原来辣么重要OTL


嗯……虽然写的丑但我就是要放代码哼唧反正只比yjq慢……嗯…………那么几秒嘛………………嗯就几秒……【bzoj续一秒大法好xxx


#include<bits/stdc++.h> 
#define MAXN 20057
using namespace std;	int n,m;
struct t1{
	long long gay[65];
	void init(long long x){
		memset(gay,0,sizeof(gay));
		for(int i=63;~i;--i)	if(x&(1ll<<i))
			{	gay[i]=x;	break;	}
	}
}dt[MAXN];
inline void merge(t1 &z,const t1 &x, const t1 &y){
	z=y;
	for(int i=63;~i;--i){
		long long k=x.gay[i];
		for(int j=i;~j;--j){
			if(z.gay[j]){
				if(k&(1ll<<j))	k^=z.gay[j];
			}
			else	if(k&(1ll<<j)){
				z.gay[j]=k;
				break;
			}
		}
	}
}

struct t2{
	int to,nxt;
}edge[MAXN<<1];	int cnt_edge=0;
int fst[MAXN];
void addedge(int x,int y){
	edge[++cnt_edge].to=y;
	edge[cnt_edge].nxt=fst[x];
	fst[x]=cnt_edge;
}

int anc[MAXN][18];
t1 rec[MAXN][18];
void jump(int x){
	for(int i=0;i<17;++i)	
		anc[x][i+1]=anc[anc[x][i]][i],
		merge(rec[x][i+1], rec[x][i],rec[anc[x][i]][i]);
}

int dpt[MAXN];
void dfs(int now){
	jump(now);
	for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
		if(edge[tmp].to==anc[now][0])	continue;
		int son=edge[tmp].to;
		anc[son][0]=now;
		rec[son][0]=dt[son];
		dpt[son]=dpt[now]+1;
		dfs(son);
	}
}


long long work(int u,int v){
	t1 rtn;	memset(rtn.gay,0,sizeof(rtn.gay));
	int d1=dpt[u],d2=dpt[v];
	if(d1<d2)	swap(u,v),swap(d1,d2);
	for(int i=17;~i;--i)	if(dpt[anc[u][i]]>=d2)	
		merge(rtn, rec[u][i],rtn), u=anc[u][i];	
	if(u!=v){
		for(int i=17;~i;--i){
			if(anc[u][i]!=anc[v][i])
				merge(rtn, rec[v][i],rtn), merge(rtn, rec[u][i],rtn),
				u=anc[u][i],v=anc[v][i];
			if(u==v)	break;
		}
		merge(rtn, dt[u],rtn), merge(rtn, dt[v],rtn);	
		merge(rtn, dt[anc[u][0]],rtn);
	} 
	else	merge(rtn, dt[u],rtn); 
	long long k=0;
	for(int i=63;~i;--i)
		if((rtn.gay[i]^k)>k)	k^=rtn.gay[i];
	return k;
}
int main(){
	freopen("1.in","r",stdin);
	freopen("orz.out","w",stdout);
	memset(dt,0,sizeof(dt));
	memset(anc,0,sizeof(anc));
	scanf("%d%d",&n,&m);
	int x,y;
	long long kk;
	for(int i=1;i<=n;++i)	scanf("%lld",&kk), dt[i].init(kk);
	for(int i=1;i<n;++i)
		scanf("%d%d",&x,&y), addedge(x,y),addedge(y,x);
	dpt[1]=0;
	anc[1][0]=1;
	dfs(1);	
	
	for(int i=1;i<=m;++i)
		scanf("%d%d",&x,&y), printf("%lld\n",work(x,y));
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值