POJ 3162 淺談尺取法區間問題運用及多源樹上路徑統計
世界真的很大
NOIP近在咫尺,已是迫在眉睫之時
今天卻還是這麼水
做完一道上週的遺留問題
這個尺取法為什麼叫這個名字我也沒搞懂
看題先:
description:
一棵n個節點的樹。wc愛跑步,跑n天,第i天從第i個節點開始跑步,每次跑到距第i個節點最遠的那個節點(產生了n個距離),現在要在這n個距離裡取連續的若干天,使得這些天裡最大距離和最小距離的差小於M,問怎麼取使得天數最多?
input:
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:
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<stdio.h>
#include<algorithm>
#include<cstring>
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
*/
嗯,就是這樣