3.28省选模拟

Future can be expectation and never give up in any case

I never agree to give up this sentence

重新玩了一下,手感还在

手感尚在

我太菜了,又垫底了

\(T1\)感知了一下是个神仙的\(dp,\)决策的时候还无法直接转移,就写了个暴力\(dp\ kill\)

\(T2\)想从图论上搞事情,然后我连周期都不会...\(graph\ theory\ kill\)

\(T3\)发现菊花和第一个部分很好拿分,链的部分并没有想到,尽管考完后被告知链最好写了.\(graph\ theory\ double \ kill\)

\(T1\)分身游走

神仙\(dp\)实锤了

首先比较好想的是\(k=1,\)除了最长链都被走了两次

\(k=2,\)如果一开始有两个分叉,然后能节省一个直径的距离

然后推导性质\(:\)

\(1.\)在最优方案中,如果进入一个子树大于两个,那么不可能都回来,如果都回来,和一个进去是一样的,显然没必要

\(2.\)如果至少两个分身进入以\(x\)为根的子树,那么这些分身都应该停在以\(x\)为根的子树内,否则的话,要么一个进去,否则都不出来

我们现在可以把\(dp\)优化到\(O(n^2k^2)\)得到\(50pts\)

那开始终极的\(dp\)

我们的时间复杂度主要是,枚举根每次需要重新跑一遍树,有很多\(dp\)转移时等价的

我们转移\(dp\)可以枚举一条边\((x,y),\)计算以\(y\)为根,\(x\)子树内部的\(dp,\)以后再使用的时候直接调取就好了

随机数据下远远达不到\(O(n^2k^2),\)惊叹于出题人的思路,就是预处理\(dp,\)以后不用转移了

至于如果怕被卡的话,拆点可以更加稳定

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define MAXN 30005
//反正我们求的是每个根的值
//拆点之后算的也是对的 
using namespace std;
int head[MAXN],nxt[MAXN],val[MAXN],to[MAXN],id[MAXN],Num,tot=1,k;
int dp[MAXN][35],Ans[35],n;
vector<pair<int,int> >rd[MAXN];
bool vis[MAXN];
void add(int u,int v,int w)
{
	 tot++;
	 to[tot]=v;
	 val[tot]=w;
	 nxt[tot]=head[u];
	 head[u]=tot;
	 tot++;
	 to[tot]=u;
	 val[tot]=w;
	 nxt[tot]=head[v];
     head[v]=tot;
}
void dfs_cd(int now)
{
	 id[now]=++Num;
	 for(int x=id[now],i=0;i<rd[now].size();i++)
	 {
	 	 int y=rd[now][i].first;
	 	 if(!id[y])
	 	 {
	 	 	 ++Num;
	 	 	 add(x,Num,0);
	 	 	 x=Num;
	 	 	 add(x,Num+1,rd[now][i].second);
	 	 	 dfs_cd(y);
	 	 }
	 }
}
void sol(int now,int fa)
{
	 if(dp[fa][0]!=INF) return ;
	 dp[fa][0]=0;
	 for(int i=head[now];i;i=nxt[i])
	 {
	 	 int y=to[i];
	 	 if(i==(fa^1)) continue;
	 	 sol(y,i);
	 	 for(int j=k;j>=1;j--)
	 	 {
	 	 	 //枚举选多少个,倒序背包
	 	 	 int tmp=INF;
			 //我们这个过程是对边dp的过程
			 //dp[now][i]表示的是以now这条边连接的两点
			 //fa->x,x子树留下i个的最大值
			 //第一个转移,是一个不留,就是全部上来
			 for(int k=0;k<=j;k++)
			 {
			 	 tmp=min(tmp,dp[fa][j-k]+dp[i][k]+val[i]*(k==0?2:k));
			 }
			 //显然我们这个每一步转移都保证了边的添加 
			 dp[fa][j]=tmp;
	 	 }
	 	 dp[fa][0]+=dp[i][0]+val[i]*2;
	 }
	 for(int i=1;i<=k;i++)
	 {
	 	 dp[fa][i]=min(dp[fa][i],dp[fa][i-1]);
	 }
}
int main()
{
	freopen("move.in","r",stdin);
	freopen("move.out","w",stdout);
	scanf("%d%d",&n,&k);
	memset(dp,0x3f,sizeof(dp));
	for(int i=1,u,v,w;i<n;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		rd[u].push_back(make_pair(v,w));
		rd[v].push_back(make_pair(u,w));
	}
    dfs_cd(1);
    for(int i=2;i<=tot;i++)
    {
    	sol(to[i],i);
    }
    for(int rt=1;rt<=n;rt++)
    {
    	int x=id[rt];
    	Ans[0]=0;
    	for(int i=head[x];i;i=nxt[i])
    	{
    		for(int l=k;l>=1;l--)
    		{
    			Ans[l]+=dp[i][0]+val[i]*2;
    			//Ans表示前若干个子树留下l的答案
				//首先我们必然先进去,然后再转移 
    			for(int j=1;j<=l;j++)
    			{
    				Ans[l]=min(Ans[l],Ans[l-j]+dp[i][j]+val[i]*j);
    			}
    		}
    		Ans[0]+=dp[i][0]+val[i]*2;
    	}
    	for(int i=1;i<=k;i++)
    	{
    		Ans[i]=min(Ans[i],Ans[i-1]);
    	}
    	cout<<Ans[k]<<endl;
    }
}

\(T2\)迷梦深层

这个题有一个正规的名字,有向图邻接矩阵的幂敛指数与周期(听上去就很强)

我们设幂敛质数为\(k\),也就是我们这个矩阵开始出现循环的位置

设周期为\(d,\)开始循环之后\(d\)为一个周期

首先考虑\(d,\)一个强联通分量的周期是所有环长度的最大公约数

较为显然,我们可以用环拼出所有长度为最大公约数倍数的循环

然后一个图的周期是所有强联通分量的周期的最小公倍数

结论\(k\)上界是\(O(n^2)\)

首先求\(d,\)我们考虑怎么找到每个联通分量里的环,

我们对于这个强连通分量\(dfs,\)当我们找到一个返祖边,长度差/环长为\(d=i-j+1\)

我们知道\(gcd(a,b)=gcd(b,a-b)\)直接\(gcd\)即可

那么还有一个\(k,\)我们有了周期,如果在大于\(k,\)那么我们往后走\(d\)就一样,否则不一样,然后简单计算一下就好了

#include<bits/stdc++.h>
#define mod 1000000007
#define int long long
#define MAXN 500005
using namespace std;
int head[MAXN],nxt[MAXN],dep[MAXN],to[MAXN],cut,tot,n,m,t;
int Sum[MAXN],col[MAXN],dfn[MAXN],low[MAXN],st[MAXN],tim,top,G,L=1;
bool Lai[MAXN],vis[MAXN],ins[MAXN];
vector<int>Fin;
set<int>zong;
struct node
{
	   int jz[205][205];
	   void Init()
	   {
	   	    memset(jz,0,sizeof(jz));
	   }
}St;
void add(int u,int v)
{
	 tot++;
	 to[tot]=v;
	 nxt[tot]=head[u];
	 head[u]=tot;
}
void tarjan(int now)
{
     dfn[now]=low[now]=++tim;
     ins[now]=true;
     st[++top]=now;
     for(int i=head[now];i;i=nxt[i])
     {
     	 int y=to[i];
     	 if(!dfn[y])
     	 {
     	 	tarjan(y);
     	 	low[now]=min(low[now],low[y]);
     	 }
     	 else if(ins[y])
     	 {
     	 	   low[now]=min(low[now],dfn[y]);
     	 }
     }
     if(low[now]==dfn[now])
     {
     	int z;
     	cut++;
     	do
     	{
     	   z=st[top--];
           ins[z]=false;
     	   col[z]=cut;
     	}while(z!=now);
     }
}
int gcd(int a,int b)
{
	if(a%b==0) return b;
	return gcd(b,a%b);
}
int lcm(int a,int b)
{
	return a/gcd(a,b)*b;
}
void dfs(int now,int now_col)
{
     Lai[now]=true;
 	 for(int i=head[now];i;i=nxt[i])
 	 {
 	 	 int y=to[i];
 	 	 if(col[y]!=now_col) continue;
 	 	 if(Lai[y])
 	 	 {
 	 	 	if(!G) G=dep[now]-dep[y]+1;
 	 	 	else if(dep[now]-dep[y]+1!=0)G=gcd(G,abs(dep[now]-dep[y]+1));
 	 	 	continue;
 	 	 }
 	 	 dep[y]=dep[now]+1;
		 dfs(y,now_col);
 	 }
}
int my_pow(int a,int b)
{
	int res=1;
	while(b)
	{
		  if(b&1)
		  {
		  	  res=(res*a)%mod;
		  }
		  a=(a*a)%mod;
		  b>>=1;
	}
	return res;
}
node mul(node a,node b)
{
	 node res;
	 res.Init();
	 for(int i=1;i<=n;i++)
	 {
	 	 for(int j=1;j<=n;j++)
	 	 {
	 	 	 for(int k=1;k<=n;k++)
	 	 	 {
	 	 	 	 res.jz[i][j]|=a.jz[i][k]&b.jz[k][j];
	 	 	 }
	 	 }
	 }
	 return res;
}
node my_jzpow(node a,int b)
{
	 node res=a;
	 b--;
	 while(b)
	 {
	 	   if(b&1)
	 	   {
	 	   	  res=mul(res,a);
	 	   }
	 	   a=mul(a,a);
	 	   b>>=1;
	 }
	 return res;
}
bool check(int mid)
{
	 node res=my_jzpow(St,mid);
     node res1=my_jzpow(St,mid+L);
     int flag=true;
     for(int i=1;i<=n;i++)
     {
     	 for(int j=1;j<=n;j++)
     	 {
     	 	 if(res.jz[i][j]!=res1.jz[i][j])
     	 	 {
     	 	 	 flag=false;
     	 	 	 goto EB;
     	 	 }
     	 }
     }
     EB:;
     return flag;
}
signed main()
{
	freopen("lost.in","r",stdin);
	freopen("lost.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&t);
    for(int i=1,u,v;i<=m;i++)
    {
    	scanf("%lld%lld",&u,&v);
    	add(u,v);
    	if(t)St.jz[u][v]=1;
    }
    for(int i=1;i<=n;i++)
    {
    	if(!dfn[i]) tarjan(i);
    }
    for(int i=1;i<=n;i++)
    {
    	if(!vis[col[i]])
    	{
    		vis[col[i]]=true;
    		G=0;
    		dfs(i,col[i]);
    		if(!G) continue;
    		Fin.push_back(G);
    	}
    }
    for(int i=0;i<Fin.size();i++)
    {
    	int now=Fin[i];
    	for(int j=2;j*j<=now;j++)
    	{
    		int res=0;
    		while(now%j==0)
    		{
    			  res++;
    			  now/=j;
    		}
    		zong.insert(j);
    		Sum[j]=max(Sum[j],res);
    	}
    	if(now) zong.insert(now);
    	Sum[now]=max(Sum[now],1ll);
    }
    L=1;
    for(set<int>::iterator it=zong.begin();it!=zong.end();it++)
    {
    	(L*=my_pow(*it,Sum[*it]))%=mod;
    }
    if(t==0)cout<<L<<" ",exit(0);
    int l=1,r=n*n,mid,ans;
    while(l<=r)
    {
    	  mid=(l+r)>>1;
    	  if(check(mid))
    	  {
    	  	  r=mid-1;
    	  	  ans=mid;
    	  }
    	  else
    	  {
    	  	  l=mid+1;
    	  }
    }
    cout<<ans<<" "<<L;
}

由于这个代码没有使用矩阵"块"速幂,只能拿\(70pts\)

下面给个矩阵块速幂板子

matrix operator * (matrix a , matrix b) {
	memset(tmp.a , 0 , sizeof(tmp.a));
    memset(matsta , 0 , sizeof(matsta));
	for (int i = 1; i <= n; i++){
		for (int j = 1 , k= 1 , l = 0; j <= n ; j++ , l++) {
			if (a[i][j])  matsta[0][i][k] |= 1 << l;
			if (j % 20 == 0)  k++ , l=0;
		}
    }
	for (int i = 1; i <= n; i++){
		for (int j = 1 , k = 1 , l = 0; j <= n; j++ , l++) {
			if (b[j][i])  matsta[1][i][k] |= 1 << l;
			if (j % 20 == 0)  k++ , l = 0;
		}
    }
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= n; j++){
			for (int k = 1; k <= K; k++){
				if (matsta[0][i][k] & matsta[1][j][k]) {
					tmp[i][j] = 1;
					break;
				}
            }
        }
    }
	return tmp;
}

\(T3\)树上游戏

部分分拿满可以得到\(70pts,\)大家眼中的难度链\(<\)菊花,我眼中的难度菊花\(<\)

第一个\(sub,O(n\times m)\)暴力不用多说,

第二个\(sub,\)菊花部分,将询问排序,先找大的,全扫一遍的不超过两个,随机下每次指针移动两次得到结果,均摊下来是\(O(m)\)

第三个\(sub,\)链部分,直接三个\(set\)分别维护,取最大就好了

正解的话,考虑一条路径的所有贡献情况

\(val_1:\)端点对子树内部做贡献

\(val_2:LCA\)对子树外做贡献

\(val_3:LCA\)的其他儿子按照\(val_1\)的方法统计贡献

\(val4:\)对于链上其他点,会向自己子树按照\(val_1\)的计算方式做贡献

实现方法\(:\)把路径拆成两条链,链上所有点去\(\max,\)其余点\(w_x\)表示所有经过此点祖先的路径贡献权值的最大值,进入一个儿子,用其他儿子最大值去更新就好了,需要亿些数据结构去维护

首先附上\(50pts\)暴力代码

#include<bits/stdc++.h>
#define MAXN 210000
using namespace std;
int head[MAXN],nxt[MAXN],val[MAXN],to[MAXN],f[MAXN],tot,n,m;
int son[MAXN],dis[MAXN],dep[MAXN],siz[MAXN],top[MAXN],lu[MAXN];
struct node
{
	   int x,y,dis,lca;
}rd[MAXN];
void add(int u,int v,int w)
{
	 tot++;
	 to[tot]=v;
	 val[tot]=w;
	 nxt[tot]=head[u];
	 head[u]=tot;
}
void dfs_pre(int now,int fa)
{
	 int maxn=-1;
	 dep[now]=dep[fa]+1;
	 siz[now]=1;
	 f[now]=fa;
	 for(int i=head[now];i;i=nxt[i])
	 {
	 	 int y=to[i];
	 	 if(y==fa) continue;
	 	 dis[y]=dis[now]+val[i];
	 	 dfs_pre(y,now);
	 	 siz[now]+=siz[y];
	 	 if(siz[y]>maxn)
	 	 {
	 	 	maxn=siz[y];
	 	 	son[now]=y;
	 	 }
	 }
}
void dfs_top(int now,int topn)
{
	 top[now]=topn;
	 if(!son[now]) return ;
     dfs_top(son[now],topn);
     for(int i=head[now];i;i=nxt[i])
     {
     	 int y=to[i];
     	 if(top[y]) continue;
     	 dfs_top(y,y);
     }
}
int LCA(int u,int v)
{
//	cout<<"LCA: "<<u<<" "<<v<<"\n";
	while(top[u]!=top[v])
	{
	      if(dep[top[u]]<dep[top[v]]) swap(u,v);
		  u=f[top[u]];	
	}
	if(dep[u]>dep[v]) swap(u,v);
	return u;
}
int LEN(int x,int y)
{
	return dis[x]+dis[y]-2*dis[LCA(x,y)];
}
bool IN(int k,int x,int y)
{
	 return LEN(x,y)==LEN(k,x)+LEN(k,y);
}
bool cmp1(node a,node b)
{
	 return a.dis>b.dis;
}
int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%d%d",&n,&m);
    if(n<=2000)
    {
    	for(int i=1,u,v,w;i<n;i++)
	    {
	    	scanf("%d%d%d",&u,&v,&w);
	    	add(u,v,w);add(v,u,w);
	    }
    	dfs_pre(1,1);
	    dfs_top(1,1);
	    for(int i=1;i<=m;i++)
	    {
	    	scanf("%d%d",&rd[i].x,&rd[i].y);
	    	rd[i].lca=LCA(rd[i].x,rd[i].y);
	    }
	    for(int i=1,res;i<=n;i++)
	    {
	    	res=0;
	    	for(int j=1;j<=m;j++)
	    	{
	    		if(IN(i,rd[j].x,rd[j].y))
	    		{
	    			res=max(res,LEN(rd[j].x,rd[j].y));
	    		}
	    		else
	    		{
	    			res=max(res,LEN(rd[j].x,i)+LEN(rd[j].y,i));
	    		}
	    	}
	    	printf("%d ",res);
	    }
    }
	else
	{
		for(int i=1,u,v,w;i<n;i++)
	    {
	    	scanf("%d%d%d",&u,&v,&w);
	    	lu[max(u,v)]=w;
		}
	    for(int i=1,u,v;i<=m;i++)
	    {
	    	scanf("%d%d",&u,&v);
            if(u>v) swap(u,v);
	    	rd[i].x=u,rd[i].y=v;
	    	if(min(u,v)==1&&max(u,v)==1)
	    	{
	    	   rd[i].dis=0;
	    	}
	    	else if(min(u,v)==1)
	    	{
	    		 rd[i].dis=lu[max(u,v)];
	    	}
	    	else
	    	{
	    		 rd[i].dis=lu[u]+lu[v];
	    	}
	    }
	    sort(rd+1,rd+1+m,cmp1);
	    int res=0;
	    for(int i=1,poi1=0,poi2=0;i<=m;i++)
	    {
	    	if(rd[i].x==1)
	    	{
	    		res=max(res,rd[i].dis);
	    	}
	    	else
	    	{
	    		if(!poi1)
	    		{
	    			poi1=i;
	    			continue;
	    		}
	    		else
	    		{
	    			res=max(res,rd[poi1].dis+rd[poi2].dis);
	    			break;
	    		}
	    	}
	    }
	    printf("%d ",res);
	    for(int i=2;i<=n;i++)
	    {
	    	bool flag=false;
	    	for(int j=1;j<=m;j++)
	    	{
	    		if(rd[j].x!=i&&rd[j].y!=i)
	    		{
	    			printf("%d ",rd[j].dis+2*lu[i]);
	    			flag=true;
	    			break;
	    		}
	    	}
	    	if(!flag)
	    	{
	    		printf("%d ",rd[1].dis);
	    	}
	    }
	}  
}

以下是正解代码

#include<bits/stdc++.h>
#define INF 1000000000
#define MAXN 200010
using namespace std;
int rd(){
    int r = 0 , w = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0') {if(ch == '-') w = -1; ch = getchar();} 
    while(ch >='0' && ch <='9') {r = r * 10 + ch -'0'; ch = getchar();}
    return r * w;
}
int n,m,Idx,cnt,tmp;
int head[MAXN],dfn[MAXN],top[MAXN],dep[MAXN],dis[MAXN],id[MAXN],fval[MAXN],siz[MAXN],son[MAXN],fa[MAXN],w1[MAXN];
struct EDGE
{
    int to,nxt,w;
};
EDGE *ed[MAXN<<1];
void add(int x,int y,int z)
{
    ed[++cnt]=new EDGE;
    ed[cnt]->to=y;
    ed[cnt]->nxt=head[x];
    ed[cnt]->w=z;
    head[x]=cnt;
}
void dfs1(int x,int f)
{
    fa[x]=f;
    dep[x]=dep[f]+1;
    siz[x]=1;
    for(int i=head[x];i;i=ed[i]->nxt)
	{
        int to=ed[i]->to;
        int w=ed[i]->w;
        if(to==f) continue;
        dis[to]=dis[x]+w;
        fval[to]=w;
        dfs1(to,x);
        siz[x]+=siz[to];
        if(siz[to]>siz[son[x]]) son[x]=to;
    }
}
void dfs2(int x,int tp)
{
    top[x]=tp;
    id[dfn[x]=++Idx]=x;
    if(son[x]) dfs2(son[x] ,tp);
    for(int i=head[x];i;i=ed[i]->nxt)
	{
        int to=ed[i]->to;
        if(to==tp||to==fa[x]||to==son[x]) continue;
        dfs2(to,to);
    }
}
namespace Segment_Tree
{
	#define ls (x<<1)
	#define rs ((x<<1)|1)
    struct node
	{
        int l,r,Max;
    };
    node tr[MAXN<<2];
    void build(int x,int l,int r)
	{
        tr[x].l=l,tr[x].r=r;
        tr[x].Max=-1;
        if(l==r) return;
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
    }
    void update(int x,int l,int r,int k)
	{
        if(l>r) return;
        if(l<=tr[x].l&&tr[x].r<=r) 
		{
            tr[x].Max=max(tr[x].Max,k);
            return;
        }
        int mid=tr[x].l+tr[x].r>>1;
        if(l<=mid) update(ls,l,r,k);
        if(r>mid)  update(rs,l,r,k);
    }
	int Getmax(int x,int pos,int now=-INF)
	{
        now=max(now,tr[x].Max);
        if(tr[x].l==tr[x].r) return now;
        int mid=tr[x].l+tr[x].r>>1;
        if(pos<=mid) return Getmax(ls,pos,now);
        else return Getmax(rs,pos,now);
    }
}
struct qr
{
    int x,y,w;
    friend bool operator < (qr x , qr y)
	{
        return x.w > y.w;
    }
};
qr P[MAXN << 1];
int pcnt;
int lca(int x , int y)
{	
    while(top[x]!=top[y])
	{
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
int Fa[MAXN];
int Find(int x)
{
    return Fa[x]==x?x:Fa[x]=Find(Fa[x]);
}
bool check(int x,int y)
{
    if(dfn[y]<=dfn[x]&&dfn[x]<=dfn[y]+siz[y]-1) return 1;
    return 0;
}
void update(int x,int y,int k)
{
    x=Find(x);
    while(dep[x]>dep[y]) w1[x]=k,Fa[x]=fa[x],x=Find(x);
}
queue<int>q;
bool vis[MAXN];
int bfn[MAXN];
void bfs()
{
    q.push(1);
    vis[1]=1;
    Idx=0;
    while(!q.empty())
	{
        int x=q.front();
        q.pop();
        bfn[x]=++Idx;
        for(int i=head[x];i;i=ed[i]->nxt)
		{
            int to=ed[i]->to;
            if(vis[to]==0) vis[to]=1,q.push(to);
        }
	}
}
int Find(int x,int y)
{
    if(x==y) return x;
    if(check(x,son[y])) return son[y];
    else while(fa[top[x]]!=y) x=fa[top[x]];
    return top[x];
}
struct line 
{
	int x,y,w;
};
vector<line> g[MAXN];
int up[MAXN],down[MAXN],ans[MAXN],L[MAXN],R[MAXN];
void init(int x,int F)
{
    ans[x]=max(ans[x],down[x]);
    for(int i=head[x];i;i=ed[i]->nxt)
	{
        int to=ed[i]->to;
        int w=ed[i]->w;
        if(to==F) continue;
        down[to]=max(down[to],down[x]+2*w);
        init(to,x);
        up[x]=max(up[x],up[to]+2*w);
	};
    ans[x]=max(ans[x],up[x]);
}
void calc(int x,int f,int s=-INF){
    int Mx=-INF;
    int sx=-INF;
    ans[x]=max(ans[x],s);
    for(int i=head[x];i;i=ed[i]->nxt)
	{
        int w=ed[i]->w;
        int to=ed[i]->to;
        if(to==f) continue;
        if(up[to]+2*w>Mx) sx=Mx,Mx=up[to]+2*w;
        else if(up[to]+2*w>sx) sx=up[to]+2*w;
    }
    for(int i=head[x];i;i=ed[i]->nxt)
	{    	
        int to=ed[i]->to;
        int w=ed[i]->w;
        if(to==f) continue;
        if(up[to]+2*w==Mx) calc(to,x,max(s,sx)+2*w);
        else calc(to,x,max(s,Mx)+2*w);
    }
}
using namespace Segment_Tree;
void dfs(int x,int f,int s=-INF)
{
    s=max(s,Getmax(1,bfn[x]));
    s+=fval[x]*2;
    int Mx=-INF;
    int sx=-INF;
    ans[x]=max(ans[x],max(w1[x],s));
    for(int i=head[x];i;i=ed[i]->nxt)
	{
        int to=ed[i]->to;
        if(w1[to]>Mx) sx=Mx,Mx=w1[to];
        else if(w1[to]>sx) sx=w1[to];
    }
    for(auto to:g[x])
	{  	
        int to1=to.x;
        int to2=to.y;
        int w=to.w;
        if(bfn[to1]>dfn[to2]) swap(to1,to2);
        update(1,L[x],bfn[to1]-1,w);
        update(1,bfn[to1]+1,bfn[to2]-1,w);
        update(1,bfn[to2]+1,R[x],w);
    }
    for(int i=head[x];i;i=ed[i]->nxt)
	{
        int to=ed[i]->to;
        if(to==f) continue;
        if(w1[to]==Mx) dfs(to,x,max(s,sx));
        else dfs(to,x,max(s,Mx));
    }
} 
void Init()
{
	memset(up,-1 ,sizeof(up));
    memset(down,-1,sizeof(down));
    memset(ans,-1,sizeof(ans));
    memset(w1,-1,sizeof(w1));
}
signed main()
{
	Init();
	n=rd();
    m=rd();
    for(int i=2;i<=n;i++) 
	{
        int x =rd(),y=rd(),z=rd();
        add(x,y,z);
        add(y,x,z);
    }
    dfs1(1,0);
    dfs2(1,1);
    bfs();
    for(int x=1;x<=n;x++)
	{
        L[x]=INF;
        Fa[x]=x;
        for(int i=head[x];i;i=ed[i]->nxt)
		{
            int to=ed[i]->to;
            if(to==fa[x]) continue;
            L[x]=min(L[x],bfn[to]);
            R[x]=max(R[x],bfn[to]);
        }
    }
    for(int i=1;i<=m;i++)
	{
        int x=rd(),y=rd();
        int LCA=lca(x,y);
        int w=dis[x]+dis[y]-2*dis[LCA];
        int fx=Find(x,LCA),fy=Find(y,LCA);
        if(x==y)
		{
            up[x]=max(up[x],0);
            down[x]=max(down[x],0);
            continue;
        }
        up[LCA]=max(up[LCA],w);
        tmp=max(tmp,w);
        if(LCA!=x) down[x]=max(down[x],w);
        if(LCA!=y) down[y]=max(down[y],w);
        if(LCA==x||LCA==y)
		{
            if(x==LCA) swap(x,y);
            P[++pcnt]=(qr){x,y,w};
            continue;
        }
        P[++pcnt]=(qr){x,y,w};
        P[++pcnt]=(qr){y,x,w};
        if(LCA!=x&&LCA!=y) g[LCA].push_back((line){fx,fy,w});
    }
    sort(P+1,P+pcnt+1);
    for(int i=1;i<=pcnt;i++) update(P[i].x,P[i].y,P[i].w);
    init(1,0);
    calc(1,0);
    dfs(1,0);
    for(int i=1;i<=n;i++)
	{
        ans[i]=max(ans[i],tmp);
        cout<<ans[i]<<" ";
    }
    return 0;
}
posted @ 2022-03-28 18:53  Authentic_k  阅读(69)  评论(0编辑  收藏  举报