杭二学习Day6——比赛

背景:

最后一天了。

T1 \text{T1} T1

que \text{que} que

设每一点 i i i到最远点的距离是 d i s i dis_i disi,求 min ⁡ { d i s i } \min\{dis_i\} min{disi}

sol \text{sol} sol

显然 a n s = ⌈ 树 的 直 径 2 ⌉ ans=\lceil \frac{树的直径}{2}\rceil ans=2
Θ ( n ) \Theta(n) Θ(n)求解即可。

code \text{code} code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
	int n,m,len=0,ma=0,st=0;
	struct node{int x,y,next;} a[1000010];
	int last[100010];
void ins(int x,int y)
{
	a[++len]=(node){x,y,last[x]}; last[x]=len;
}
void dfs(int x,int fa,int tot)
{
	if(tot>ma) ma=tot,st=x;
	for(int i=last[x];i;i=a[i].next)
	{
		int y=a[i].y;
		if(y==fa) continue;
		dfs(y,x,tot+1);
	}
}
int main()
{
	int x,y;
//	freopen("A.in","r",stdin);
//	freopen("A.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%d %d",&x,&y);
		ins(x,y),ins(y,x);
	}
	dfs(1,0,0);
	dfs(st,0,0);
	printf("%d\n",(ma+1)/2);
}


T2 \text{T2} T2

que \text{que} que

给定一个序列 a a a,多组询问给出 x , y x,y x,y,求 x x x y y y区间选 3 3 3个数作为边长,能得到的最大的三角形的周长。
∀ i ∈ { [ 1 , n ] ∩ N + } , a i ≤ 1 0 9 ∀i∈\{[1,n]∩N_+\},a_i≤10^9 i{[1,n]N+},ai109

sol \text{sol} sol

考场上想出了正解,结果不小心把自己假 hack \text{hack} hack掉了,呜呜呜。
不难发现将 x x x y y y区间降序排序,结果一定是相邻的三个数组成的三角形。
一种暴力就是排序后判断相邻的三个数能否组成三角形,求周长即可。

考虑无解的最坏情况。
其实就是斐波那契数列。
由于斐波那契数列增长极快,在 50 50 50左右就超过 1 0 9 10^9 109
其实在考场上我也想到了,但是用 1 , 1 , 1 , . . . , 1 1,1,1,...,1 1,1,1,...,1假的 hack \text{hack} hack掉了自己。

那么用线段树维护区间最值,每找到一个最大值将其变为 0 0 0,知道已经做了 50 50 50个数或找到了可以构成三角形的方案。
这样的时间复杂度是 Θ ( 50 n log ⁡ n ) \Theta(50n\log n) Θ(50nlogn)
卡卡常,即可通过。

code \text{code} code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define LL long long
using namespace std;
	struct node1{int l,r,lc,rc,d,ma,id;} tr[400010];
	int n,m,len=0;
	struct node2{int d,id;} d[100010];
void build(int l,int r)
{
	int now=++len,mid=(l+r)>>1;
	tr[now]=(node1){l,r,-1,-1,0,0,0};
	if(l<r)
	{
		tr[now].lc=len+1,build(l,mid);
		tr[now].rc=len+1,build(mid+1,r);
	}
}
void change(int now,int x,int d,int id)
{
	if(tr[now].l==tr[now].r)
	{
		tr[now].d=tr[now].ma=d;
		tr[now].id=id;
		return;
	}
	int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
	if(x>mid) change(rc,x,d,id); else change(lc,x,d,id);
	if(tr[lc].ma>tr[rc].ma) tr[now].ma=tr[lc].ma,tr[now].id=tr[lc].id; else tr[now].ma=tr[rc].ma,tr[now].id=tr[rc].id;
}
node2 findmax(int now,int l,int r)
{
	if(tr[now].l==l&&tr[now].r==r) return (node2){tr[now].ma,tr[now].id};
	int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
	if(r<=mid) return findmax(lc,l,r);
	else if(l>mid) return findmax(rc,l,r);
	else
	{
		node2 t1=findmax(lc,l,mid),t2=findmax(rc,mid+1,r);
		if(t1.d>t2.d) return t1; else return t2;
	}
}
int main()
{
	int x,y;
	freopen("B.in","r",stdin);
	freopen("B.out","w",stdout);
	scanf("%d %d",&n,&m);
	build(1,n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&x);
		change(1,i,x,i);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d",&x,&y);
		if(y-x+1<3)
		{
			printf("-1\n");
			continue;
		}
		int st=0;
		bool bz=false;
		while(st<y-x+1&&st<=50)
		{
			d[++st]=findmax(1,x,y);
			change(1,d[st].id,0,d[st].id);
			if(st>=3&&d[st].d+d[st-1].d>d[st-2].d)
			{
				bz=true;
				break;
			}
		}
		if(!bz) printf("-1\n"); else printf("%lld\n",(LL)d[st].d+d[st-1].d+d[st-2].d);
		for(int j=1;j<=st;j++)
			change(1,d[j].id,d[j].d,d[j].id);
	}
}


T3 \text{T3} T3

que \text{que} que

一个字符串,多组询问给出 x , y x,y x,y,求以 i ∈ { [ x , y ] ∩ N + } i∈\{[x,y]∩N_+\} i{[x,y]N+}结尾的字符串的最长公共后缀。

sol \text{sol} sol

正解是 SAM \text{SAM} SAM,一直没有学,先坑着。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值