#199. 守护糖果

不想压代码了,我要吐了,就随便讲一下思路吧。

首先要说明,封锁条件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;
}


import numpy as np import random from resourse import ICA, Country, Empire, Colony, decode,evaluate import matplotlib.pylab as plt import time start = time.time() ica = ICA() best1 = [10, 16, 17, 1, 4, 7, 13, 11, 12, 5, 8, 2, 14, 9, 15, 3, 6, 3, 4, 3, 1, 2, 2, 3, 5, 4, 1, 1, 2, 4, 4, 4, 2, 3] best2 = [1, 5, 12, 11, 14, 2, 10, 4, 6, 7, 17, 16, 3, 8, 13, 9, 15, 5, 4, 1, 4, 1, 1, 1, 3, 3, 5, 2, 4, 3, 5, 2, 4, 3] best3 = [7, 10, 17, 12, 4, 14, 1, 2, 11, 15, 13, 9, 16, 6, 5, 8, 3, 4, 4, 5, 3, 1, 3, 2, 3, 1, 3, 4, 4, 1, 4, 2, 2, 5] bestlst = [best1,best2, best3] country = ica.createCountries() # for num, blst in enumerate(bestlst): # ica.countries[num].ind = blst # ica.countries[num].cost= evaluate(blst) ica.createEmpires() empire = ica.empires # """ index = 1 plt.ion() while len(empire) != 1: empire = ica.empires ica.moveAction() ica.compare() ica.compete() ica.weedOut() ica.revolution() empiresCost = [e.getempirecost() for e in empire] print("第{}伦 -- {}".format(index, empiresCost)) print("帝国数: {} , 殖民地数: {}".format(len(ica.empires), len(ica.colonies))) minEmpiresCost = np.argmin(empiresCost) marsEmpire = empire[minEmpiresCost] # print("第{}伦 -- 战神 :{}".format(index, marsEmpire.ind)) index += 1 print() # plt.pause(0.05) # plt.show() print("cost: {} ,最终坐标: {} ".format(empire[0].cost, empire[0].getPosit())) print(decode(empire[0].getPosit())) # plt.show() # plt.ioff() # """ end = time.time() print("程序process_1的运行时间为:{}s".format(end - start))
04-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值