题解 我醉

传送门

将「x 连向 y 的边」理解成有向边,70pts暴力挂没了
向出题人致以亲切的问候

  • 处理树上回文路径的一种方法:
    若已知回文串长度为 \(L\),尝试点分治,发现一条回文路径一定被分为一长一短两端
    考虑枚举长链,发现短链长度可以表示为 \(L-len_{longchain}\)
    于是可以 hash 判断短链是否存在,然后同样 hash 判断剩下那段是否回文即可
    具体地,判断剩下那段是否回文可以维护两个方向的 hash 实现
    维护逆向的 hash 其实也很简单,有 \(rh[i]=rh[i-1]+s[i]*pw[i]\)

于是回到这道题,二分答案,点分治 check 即可
注意回文分奇偶,存在一段长为 \(i+1\) 的回文路径不一定存在一段长为 \(i\) 的回文路径
所以要按奇偶分开二分取最大值

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
#define ull unsigned long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
bool del[N];
ull pw[N], h[N], rh[N];
int head[N], size;
int siz[N], msiz[N], rot, mid, top;
const ull base=13131;
// unordered_map<ull, int> mp;
struct edge{int to, next, val;}e[N<<1];
inline void add(int s, int t, int w) {e[++size]={t, head[s], w}; head[s]=size;}
inline ull hashing(int l, int r) {return l>r?0:(h[r]-h[l-1]*pw[r-l+1]);}
// int tl[N<<2], tr[N<<2], len[N<<2]; ull dat[N<<2];
// #define tl(p) tl[p]
// #define tr(p) tr[p]
// #define len(p) len[p]
// #define dat(p) dat[p]
// #define pushup(p) dat(p)=dat(p<<1)*pw[len(p<<1|1)]+dat(p<<1|1)
// void build(int p, int l, int r) {
// 	tl(p)=l; tr(p)=r; len(p)=r-l+1;
// 	if (l==r) return ;
// 	int mid=(l+r)>>1;
// 	build(p<<1, l, mid);
// 	build(p<<1|1, mid+1, r);
// }
// void upd(int p, int pos, ull val) {
// 	if (tl(p)==tr(p)) return void(dat(p)=val);
// 	int mid=(tl(p)+tr(p))>>1;
// 	if (pos<=mid) upd(p<<1, pos, val);
// 	else upd(p<<1|1, pos, val);
// 	pushup(p);
// }
// ull query(int p, int l, int r) {
// 	if (l<=tl(p)&&r>=tr(p)) return dat(p);
// 	int mid=(tl(p)+tr(p))>>1;
// 	if (l<=mid && r>mid) return query(p<<1, l, r)*pw[r-mid]+query(p<<1|1, l, r);
// 	else if (l<=mid) return query(p<<1, l, r);
// 	else return query(p<<1|1, l, r);
// }
struct hash_map{
	static const int SIZE=1000010;
	int head[SIZE], sta[SIZE], size, top;
	struct node{int val, next; ull dat;}e[SIZE<<1];
	hash_map(){memset(head, -1, sizeof(head));}
	inline int end() {return -1;}
	inline int& operator [] (ull t) {
		ull t2=t*98244353%SIZE;
		if (head[t2]==-1) sta[++top]=t2;
		for (int i=head[t2]; ~i; i=e[i].next)
			if (e[i].dat==t) return e[i].val;
		e[++size]={0, head[t2], t}; head[t2]=size;
		return e[size].val;
	}
	inline int find(ull t) {
		ull t2=t*98244353%SIZE;
		for (int i=head[t2]; ~i; i=e[i].next)
			if (e[i].dat==t) return 1;
		return -1;
	}
	void clear() {
		while (top) head[sta[top--]]=-1;
		size=0;
	}
}mp;
void push(int val) {
	++top;
	h[top]=h[top-1]*base+val;
	// upd(1, top, val);
	rh[top]=rh[top-1]+val*pw[top-1];
}
void pop() {--top;}
bool ispal(int l, int r) {
	// cout<<"ispal: "<<l<<' '<<r<<endl;
	if (l>=r) return 1;
	int len=(l+r)>>1;
	ull h1=rh[l+len-1], h2=hashing(r-len+1, r);
	// cout<<"h: "<<h1<<' '<<h2<<endl;
	return h1==h2;
}

void getrt(int u, int fa, int tot) {
	// cout<<"getrt: "<<u<<' '<<fa<<' '<<tot<<endl;
	siz[u]=msiz[u]=1;
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		if (del[v]||v==fa) continue;
		getrt(v, u, tot);
		msiz[u]=max(msiz[u], siz[v]);
		siz[u]+=siz[v];
	}
	msiz[u]=max(msiz[u], tot-siz[u]);
	// cout<<"msiz: "<<u<<' '<<msiz[u]<<endl;
	if (msiz[u]<msiz[rot]) rot=u;
}

void dfs1(int u, int fa, int dis, ull pre, int op) {
	// cout<<"dfs1: "<<u<<endl;
	if (dis>mid/2) return ;
	mp[pre]+=op; //, cout<<"u: "<<u<<endl;
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		if (del[v]||v==fa) continue;
		dfs1(v, u, dis+1, pre*base+e[i].val, op);
	}
}

bool dfs2(int u, int fa, int dis) {
	//cout<<"dfs2: "<<u<<' '<<fa<<' '<<dis<<endl;
	if (dis>mid) return 0;
	if (dis>=(mid+1)/2) {
		int len=mid-dis;
		ull t=hashing(dis-len+1, dis);
		// if (u==9) {
		// 	cout<<"h: "; for (int i=1; i<=top; ++i) cout<<h[i]<<' '; cout<<endl;
		// 	cout<<"t: "<<t<<endl, cout<<"len: "<<len<<endl;
		// 	cout<<"mp: "<<mp[t]<<endl;
		// 	cout<<"ispal: "<<ispal(1, dis-len)<<' '<<dis-len<<endl;
		// }
		if (mp.find(t)!=mp.end() && mp[t] && ispal(1, dis-len)) return 1;
	}
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		if (del[v]||v==fa) continue;
		push(e[i].val);
		if (!dis) dfs1(v, u, 1, e[i].val, -1);
		if (dfs2(v, u, dis+1)) return 1;
		if (!dis) dfs1(v, u, 1, e[i].val, 1);
		pop();
	}
	return 0;
}

bool calc(int u) {
	// cout<<"calc: "<<u<<endl;
	mp.clear();
	dfs1(u, 0, 0, 0, 1);
	// cout<<"after dfs1"<<endl;
	// for (auto it:mp) cout<<"("<<it.fir<<','<<it.sec<<")"<<' '; cout<<endl;
	return dfs2(u, 0, 0);
}

bool solve(int u) {
	// cout<<"solve: "<<u<<endl;
	del[u]=1;
	if (calc(u)) return 1;
	// cout<<"pos2"<<endl;
	for (int i=head[u],v; ~i; i=e[i].next) {
		v = e[i].to;
		if (del[v]) continue;
		rot=0;
		getrt(v, 0, siz[v]);
		if (solve(rot)) return 1;
	}
	return 0;
}

bool check() {
	// cout<<"check: "<<mid<<endl;
	memset(del, 0, sizeof(del));
	memset(msiz, 0, sizeof(msiz));
	msiz[rot=0]=n; top=0;
	getrt(1, 0, n);
	// cout<<"rot: "<<rot<<endl;
	bool ans=solve(rot);
	// cout<<"return: "<<ans<<endl;
	return ans;
}

signed main()
{
	freopen("name.in", "r", stdin);
	freopen("name.out", "w", stdout);

	n=read();
	memset(head, -1, sizeof(head));
	for (int i=1,u,v,w; i<n; ++i) {
		u=read(); v=read(); w=read();
		add(u, v, w); add(v, u, w);
	}
	// build(1, 1, n);
	pw[0]=1;
	for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
	int l=1, r=min(n/2, 2000), now, ans=1;
	// mid=4; check();
	while (l<=r) {
		now=(l+r)>>1;
		mid=now<<1;
		if (check()) l=now+1;
		else r=now-1;
	}
	ans=max(ans, (l-1)<<1);
	l=1, r=min((n-1)/2, 2000);
	while (l<=r) {
		now=(l+r)>>1;
		mid=now<<1|1;
		if (check()) l=now+1;
		else r=now-1;
	}
	ans=max(ans, (l-1)<<1|1);
	// for (int i=1; i<=n; ++i) mid=i, cout<<"check: "<<check()<<endl;
	printf("%d\n", ans);
	
	return 0;
}
posted @ 2022-02-07 19:03  Administrator-09  阅读(0)  评论(0编辑  收藏  举报