不想压代码了,我要吐了,就随便讲一下思路吧。
首先要说明,封锁条件4是没有用的。可以用反证法证明。
证毕。
接下来先不考虑x,题目变为求树上随机n条链组成的网的边权和最大值。
考虑只有一条链的情况,很显然要选直径。
接下来选的每一条链都要求经过原连通块,所以干脆取直径上一点为根重新建树,然后每次加两条链,要求链的两端分别为叶节点和原连通块内的一点。然后发现应该用长链剖分来解决。(树链剖分的另一种方式,和重链剖分没有太大的区别,只不过变成了让每个节点的son指向深度最大的节点所在的子树的根罢了。)
然后直接将每条链的边权和sort,从大到小加到图里就好了。
再考虑x,第一反应是,先取2y-2条边,再加一条x在的符合要求的贡献最大的链。若x已在原连通块中,就直接去2y-1条边。然后发现这是错的233。
我们发现在这棵树上,绿方案比红方案不知道高到哪里去了。
所以得到第二种更优的策略:先取2y-1条链,然后让这个点连向x,再让x连向子最深的叶节点。然后发现还是错的、、
发现只选一条链时有可能不经过根,所以需要特判。(当然选两条以上是必经的)
然后代码被我写臭了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define ll long long
#define db double
#define ldb long double
#define pii pair<int,int>
#define mkp make_pair
#define X first
#define Y second
const int N=100005;
int n,ans;
struct POINT{int K,W,ne;}P[N<<1];
int tot,he[N],rt,dep[N],dad[N],son[N],pre[N],len[N];
int flg[N],val[N],pos[N],cnt,sa[N],rk[N],sum[N];
void add(int x,int y,int z){
P[++tot]=(POINT){y,z,he[x]};he[x]=tot;
}
void DFS(int x,int fa){
int p,y;
if(dep[x]>dep[rt])rt=x;
for(p=he[x];p;p=P[p].ne)if((y=P[p].K)!=fa){
dep[y]=P[p].W+dep[x];DFS(y,x);
}
}
void DFS1(int x,int fa){
int y,p;
for(p=he[x];p;p=P[p].ne)if((y=P[p].K)!=fa){
dep[y]=P[p].W+dep[x];DFS1(y,pre[y]=x);
if(!son[x]||dep[son[x]]+len[son[x]]<len[y]+dep[y])
len[x]=P[p].W+len[son[x]=y];
}
}
void DFS2(int x,int e){
int p;
if(son[pre[x]]==x)dad[x]=dad[pre[x]];
else{
flg[dad[x]=x]=++cnt;pos[cnt]=x;val[cnt]=len[x]+P[e].W;
}
for(p=he[x];p;p=P[p].ne)if(p!=e){
DFS2(P[p].K,p^1);
}
}
bool cmp(int x,int y){
if(pos[x]==rt)return 1;
if(pos[y]==rt)return 0;
return val[x]>val[y];
}
int main(){
// freopen("r.in","r",stdin);
// freopen("w.out","w",stdout);
int i,Q,x,y,z;
scanf("%d%d",&n,&Q);tot=1;
per(i,n-1,1){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
DFS(1,0);dep[rt]=0;
DFS1(rt,0);DFS2(rt,0);
rep(i,1,cnt)sa[i]=i;
sort(sa+1,sa+cnt+1,cmp);
rep(i,1,cnt)rk[sa[i]]=i;
rep(i,1,cnt)sum[i]=sum[i-1]+val[sa[i]];
while(Q--){
scanf("%d%d",&x,&y);
x=(x+ans-1)%n+1,y=(y+ans-1)%n+1;
if(rk[flg[dad[x]]]<=(y<<1)-1)
printf("%d\n",ans=sum[min((y<<1)-1,cnt)]);
else{
for(z=dad[x];rk[flg[dad[pre[z]]]]>(y<<1)-2;z=dad[pre[z]]);
ans=sum[(y<<1)-2]+len[x]+dep[x]-dep[pre[z]];
for(z=dad[x];rk[flg[dad[pre[z]]]]>(y<<1)-1;z=dad[pre[z]]);
if(pre[z])z=pre[z];
ans=max(ans,sum[(y<<1)-1]+len[x]+dep[x]-dep[z]-min(len[z],dep[z]));
printf("%d\n",ans);
}
}
return 0;
}
24

被折叠的 条评论
为什么被折叠?



