题解 我醉
将「x 连向 y 的边」理解成有向边,70pts暴力挂没了
向出题人致以亲切的问候
- 处理树上回文路径的一种方法:
若已知回文串长度为 ,尝试点分治,发现一条回文路径一定被分为一长一短两端
考虑枚举长链,发现短链长度可以表示为
于是可以 hash 判断短链是否存在,然后同样 hash 判断剩下那段是否回文即可
具体地,判断剩下那段是否回文可以维护两个方向的 hash 实现
维护逆向的 hash 其实也很简单,有
于是回到这道题,二分答案,点分治 check 即可
注意回文分奇偶,存在一段长为 的回文路径不一定存在一段长为 的回文路径
所以要按奇偶分开二分取最大值
点击查看代码
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】