1. 程式人生 > >POJ 3162 淺談尺取法區間問題運用及多源樹上路徑統計

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 */

嗯,就是這樣