世界真的很大
NOIP近在咫尺,已是迫在眉睫之时
今天却还是这么水
做完一道上周的遗留问题
这个尺取法为什么叫这个名字我也没搞懂
看题先:
一棵n个节点的树。wc爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要在这n个距离里取连续的若干天,使得这些天里最大距离和最小距离的差小于M,问怎么取使得天数最多?
The input contains a single test case.
The test case starts with a line containing the integers N (N ≤ 106) and M (M < 109).
Then follow N − 1 lines, each containing two integers fi and di (i = 1, 2, …, N − 1), meaning the check-points i + 1 and fi are connected by a path of length di.
Output one line with only the desired number of days in the longest series.
这个问题分为两个部分
一是求树上每个点在树上的最远点对,二是在给定序列中选取最长的一段使得这一段的最值之差小于等于m
对于第一个问题,同 HDU 2196
现在只需要处理第二个问题了
求出树上最长一段连续区间,其最值之差小于等于m
直接枚举区间n^25不现实,我们需要一个O(n)的做法
这里介绍一个尺取法
所谓尺取法,也不知道具体来说是啥
使用两个指针,如果当前区间的最值之差小于等于m,右指针++,表示可以更新答案
否则左指针++,表示区间需要缩减
大概就是这样
没想到写出来这么短233
维护区间最值可以用ST表,线段树,单调队列等等
鉴于想要练习一下数据结构于是就写了线段树233
表示直到现在还是不会树状数组,也懒得学了
完整代码:
#include
#include
#include
using namespace std;
const int INF=0x3f3f3f3f;
struct node
{
int mx,mn;
node *ls,*rs;
void update()
{
mx=max(ls->mx,rs->mx);
mn=min(ls->mn,rs->mn);
}
}pool[4000010],*tail=pool,*root;
struct edge
{
int v,w,last;
}ed[2000010];
int n,m,num=0;
int down[1000010][2],up[1000010],a[1000010],head[1000010],son[1000010];
void init()
{
num=0,tail=pool;
memset(down,0,sizeof(down));
memset(head,0,sizeof(head));
memset(son,0,sizeof(son));
memset(up,0,sizeof(up));
memset(a,0,sizeof(a));
}
node *build(int lf,int rg)
{
node *nd=++tail;
if(lf==rg)
{
nd->mx=nd->mn=a[lf];
return nd;
}
int mid=(lf+rg)>>1;
nd->ls=build(lf,mid);
nd->rs=build(mid+1,rg);
nd->update();
return nd;
}
void add(int u,int v,int w)
{
num++;
ed[num].v=v;
ed[num].w=w;
ed[num].last=head[u];
head[u]=num;
}
void dfs1(int u,int f)
{
for(int i=head[u];i;i=ed[i].last)
{
int v=ed[i].v;
if(v==f) continue ;
dfs1(v,u);
if(down[v][0]+ed[i].w>=down[u][0])
down[u][1]=down[u][0],down[u][0]=down[v][0]+ed[i].w,son[u]=v;
else if(down[v][0]+ed[i].w>down[u][1])
down[u][1]=down[v][0]+ed[i].w;
}
}
void dfs2(int u,int f)
{
for(int i=head[u];i;i=ed[i].last)
{
int v=ed[i].v;
if(v==f) continue ;
if(v==son[u])
up[v]=max(up[u],down[u][1])+ed[i].w;
else up[v]=max(up[u],down[u][0])+ed[i].w;
dfs2(v,u);
}
}
void query(node *nd,int lf,int rg,int L,int R,int &A,int &B)
{
if(L<=lf && rg<=R)
{
A=nd->mx,B=nd->mn;
return ;
}
int mid=(lf+rg)>>1,a1=0,a2=0,b1=INF,b2=INF;
if(L<=mid) query(nd->ls,lf,mid,L,R,a1,b1);
if(R>mid) query(nd->rs,mid+1,rg,L,R,a2,b2);
A=max(a1,a2),B=min(b1,b2);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=2;i<=n;i++)
{
int v,w;
scanf("%d%d",&v,&w);
add(i,v,w),add(v,i,w);
}
dfs1(1,1);
dfs2(1,1);
for(int i=1;i<=n;i++)
a[i]=max(down[i][0],up[i]);
root=build(1,n);
int i=1,j=1,ans=0;
while(j<=n && i<=j)
{
int mx,mn;
query(root,1,n,i,j,mx,mn);
if(mx-mn<=m) ans=max(ans,j-i+1),j++;
else i++;
}
printf("%d\n",ans);
}
return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/
嗯,就是这样