#10056. 「一本通 2.3 练习 5」The XOR-longest Path

题目描述

有一棵带权树,求这些边组成的路径的最大异或和。

Solution

考场 SPFA 神奇 70 分代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<ctime>

const int MAXN=100010;
using namespace std;

struct node{
	int x,y,d,next;
}e[MAXN+MAXN+10];
int len=0;
int first[MAXN+10];
int n;
int ans=0;
queue<int> q;
int f[MAXN+10];
int sx,sy,sd;
bool v[MAXN+10];

void ins(int x,int y,int d){
	e[++len].x=x;e[len].y=y;e[len].d=d;
	e[len].next=first[x];first[x]=len;
}
int max(int x,int y){
	if(x>y) return x;
	return y;
}
int work(int X){
	if(clock()>950) return 0;
	memset(f,0,sizeof(f));
	while(!q.empty()) q.pop();
	q.push(X);
	while(!q.empty()){
		int x=q.front();q.pop();v[x]=0;
		for(int i=first[x];i;i=e[i].next){
			int y=e[i].y;
			if((f[y]<(f[x]^e[i].d))&&y!=X&&v[y]){
				v[y]=0;
				f[y]=(f[x]^e[i].d);
				q.push(y);
			}
		}
		v[x]=1;
	}
	int sum=0;
	for(int i=1;i<=n;++i)
		if(i!=X) sum=max(sum,f[i]);
	return sum;
}
inline int read(){
	int x=0; char c;
	do c=getchar(); while(c<'0'||c>'9');
	while(c>='0'&&c<='9')
		x=x*10+c-48,c=getchar();
	return x;
}
int main(){
	freopen("xor.in","r",stdin);
	freopen("xor.out","w",stdout);
	n=read();
	memset(first,0,sizeof(first));
	memset(v,1,sizeof(v));
	for(int i=1;i<n;++i){
		sx=read();sy=read();sd=read();
		ins(sx,sy,sd);ins(sy,sx,sd);
	}
	for(int i=1;i<=n;++i)
		ans=max(ans,work(i));
	printf("%d",ans);
}

你现在选出了一个点,你要在剩下的 n1n-1 个中找一个点使异或最大。

假设你第一位是 0,那你肯定想找个 1 对吧。这样一直做下去就是答案。于是我们想到了 trie 树。把根到每个点的距离做出来,加进 trie 树里面,然后做一次的复杂度就是 logn\log n 的,总的复杂度就是 O(nlogn)O(n\log n) 的。

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define reg register


typedef long long ll;

int n;
ll a[100010];
ll pow[35]={1};
struct node{
	int x,fa,h,s[2];
}e[3300010];
int len=0;
ll ans=-1;

ll max(ll x,ll y) {
	return x>y?x:y;
}
inline ll read(){
	ll x=0;char c;
	do c=getchar(); while(c<'0'||c>'9');
	while(c>='0'&&c<='9')
		x=x*10+c-48,c=getchar();
	return x;
}
void ins(ll x,int root){
	if(e[root].h<=0) return;
	ll yy=pow[e[root].h-1],xx=bool(x>=yy);
	if(!e[root].s[xx]){
		e[root].s[xx]=++len;
		e[len].fa=root;e[len].h=e[root].h-1;e[len].x=xx;
	}
	ins(x-(xx?yy:0),e[root].s[xx]);
}
ll query(int x){
	ll sum=0,tf=1;
	for(reg int i=0;;){
		if(!i&&!tf) break;
		if(!i&&tf) tf=0;
		if(pow[e[i].h-1]<=x){
			x-=pow[e[i].h-1];
			if(e[i].s[0]){
				sum+=pow[e[i].h-1];
				i=e[i].s[0];
				continue;
			}
			else
				i=e[i].s[1];
		}
		else{
			if(e[i].s[1]){
				sum+=pow[e[i].h-1];
				i=e[i].s[1];
				continue;
			}
			else
				i=e[i].s[0];
		}
	}
	return sum;
}
int main(){
	memset(e,0,sizeof(e));
	for(reg int i=1;i<=31;++i)
		pow[i]=pow[i-1]*2l;
	e[0].h=31;
	scanf("%d",&n);
	for(reg int i=1;i<=n;++i){
		a[i]=read();
		ins(a[i],0);
		if(i!=1) ans=max(ans,query(a[i]));
	}
	printf("%lld",ans);
}
posted @ 2019-07-19 16:31  TeacherDai  阅读(142)  评论(0)    收藏  举报