背景:
最后一天了。
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+},ai≤109
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,一直没有学,先坑着。