https://www.luogu.org/problemnew/show/P4220
先写了暴力分的44分。那个两棵树、其中一棵是编号连续的链、边权都是1的点好像可以线段树合并,但没写。
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; ll rdn() { ll ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } ll Mx(ll a,ll b){return a>b?a:b;} const int N=1e5+5,M=3005,K=20; int n,hd[3][N],xnt,to[3][N<<1],nxt[3][N<<1]; ll w[3][N<<1],dis[N],ans,ds2[M][M]; bool flag; void add(int t,int x,int y,ll z){to[t][++xnt]=y;nxt[t][xnt]=hd[t][x];hd[t][x]=xnt;w[t][xnt]=z;} void chk(int cr,int fa) { for(int i=hd[0][cr],v;i;i=nxt[0][i]) if((v=to[0][i])!=fa) { bool fg=0;ll tw; for(int j=hd[1][cr];j;j=nxt[1][j]) if(to[1][j]==v){fg=1;tw=w[1][j];break;} if(!fg||tw!=w[0][i]){flag=1;return;} for(int j=hd[2][cr];j;j=nxt[2][j]) if(to[2][j]==v){fg=1;tw=w[2][j];break;} if(!fg||tw!=w[0][i]){flag=1;return;} chk(v,cr);if(flag)return; } } void dfs1(int cr,int fa) { ll mx=0,mx2=0; for(int i=hd[0][cr],v;i;i=nxt[0][i]) if((v=to[0][i])!=fa) { dfs1(v,cr);ll tp=dis[v]+w[0][i]; if(tp>mx)mx2=mx,mx=tp; else if(tp>mx2)mx2=tp; } ans=Mx(ans,mx+mx2);dis[cr]=mx; } void dfs2(int cr,int fa,ll lj,int t,int rt) { ds2[rt][cr]+=lj; for(int i=hd[t][cr],v;i;i=nxt[t][i]) if((v=to[t][i])!=fa)dfs2(v,cr,lj+w[t][i],t,rt); } void solve2() { for(int t=0;t<3;t++) for(int i=1;i<=n;i++)dfs2(i,0,0,t,i); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++)ans=Mx(ans,ds2[i][j]); printf("%lld ",ans); } int main() { n=rdn(); for(int t=0;t<3;t++) { ll z;xnt=0; for(int i=1,u,v;i<n;i++) u=rdn(),v=rdn(),z=rdn(),add(t,u,v,z),add(t,v,u,z); } if(n<=3000){solve2();return 0;} chk(1,0);if(!flag){dfs1(1,0);printf("%lld ",ans*3);return 0;} return 0; }
正解要边分治和虚树,现在还不会。所以用了随机化。
卡时间可以调用 clock() ,返回的是 CPU 周期,CLOCKS_PER_SEC 返回的是一秒运行了几个 CPU 周期,所以 clock() / CLOCKS_PER_SEC 可以算出运行了几秒。
随机一个根,暴力算每个点到这个根的距离(3个距离求和),把距离当前根最远的那个点设为新的根,同时更新答案。做几次之后就再随机一个根。这个间隙可以小一些,10或者8之类的。
可以打 vis[ ] 标记,作过根的点就不再作根了。
还是通不过 UOJ 的 hack 数据。
#include<cstdio> #include<cstring> #include<algorithm> #include<ctime> #define ll long long #define db double using namespace std; ll rdn() { ll ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } ll Mx(ll a,ll b){return a>b?a:b;} const int N=1e5+5,TL=3850; int n,hd[3][N],xnt,to[3][N<<1],nxt[3][N<<1]; ll w[3][N<<1],dis[N],ds1[3005][3005],ans; bool vis[N]; void add(int t,int x,int y,ll z){to[t][++xnt]=y;nxt[t][xnt]=hd[t][x];hd[t][x]=xnt;w[t][xnt]=z;} int clk(){return (db)clock()/CLOCKS_PER_SEC*1000;}//ms void dfs1(int cr,int fa,ll lj,int t,int rt) { ds1[rt][cr]+=lj; for(int i=hd[t][cr],v;i;i=nxt[t][i]) if((v=to[t][i])!=fa)dfs1(v,cr,lj+w[t][i],t,rt); } void solve1() { for(int t=0;t<3;t++) for(int i=1;i<=n;i++)dfs1(i,0,0,t,i); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++)ans=Mx(ans,ds1[i][j]); printf("%lld ",ans); } void dfs(int cr,int fa,ll lj,int t) { dis[cr]+=lj; for(int i=hd[t][cr],v;i;i=nxt[t][i]) if((v=to[t][i])!=fa)dfs(v,cr,lj+w[t][i],t); } int cz(int rt) { for(int i=1;i<=n;i++)dis[i]=0; for(int t=0;t<3;t++)dfs(rt,0,0,t); int ret=0; for(int i=1;i<=n;i++) { if(dis[i]>ans)ans=dis[i]; if(!vis[i]&&dis[i]>dis[ret])ret=i; } return ret; } int main() { n=rdn();ll z; for(int t=0;t<3;t++,xnt=0) for(int i=1,u,v;i<n;i++) u=rdn(),v=rdn(),z=rdn(),add(t,u,v,z),add(t,v,u,z); if(n<=5000){solve1();return 0;} int st=clk(); srand(time(0));srand(rand()); int rt=rand()%n+1,T=0; while(clk()-st<TL) { T++; if(T==8)rt=rand()%n+1,T=0; if(vis[rt]){T=7;continue;}vis[rt]=1; rt=cz(rt);if(!rt)break; } printf("%lld ",ans); return 0; }