「題解」:樹

問題 A: 樹subset

時間限制: 1 Sec  內存限制: 512 MBc++

題面


題面謝絕公開。ui

題解


我寫的是賽時yy的錯解哇QAQ。僥倖AC了……不過攢一種思路挺好的。spa

開始寫的是純暴力。觀察發現其中的一些點對答案並無貢獻。因此類比並查集想到了路徑壓縮。xml

能夠對於每個點映射一下父節點中第一個比它大的元素,記錄下來。每次跳躍只須要跳向這個節點便可。blog

考慮鏈上相似問題怎麼解決?那顯然是單調棧啊。遞歸

樹上單調棧怎麼搞??ip

因而我開了一個垃圾棧,用來存儲每一次從單調棧裏面pop出來的信息。再對每一次dfs記錄一個lin,爲我當前節點在垃圾棧中「寄存」的元素個數。因爲遞歸順序是肯定的,因此能夠準確「認領」回來。內存

代碼:ci

#include<bits/stdc++.h>
#define rint register int
using namespace std;
const int N=100005;
inline void read(int &a)
{
	a=0;int b=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+ch-'0';ch=getchar();}
	a=a*b;return ;
}
int n,q,w[N],f[N],ans,sta[N],tp,rb[N],rp,dep[N];
int v[N<<1],nxt[N<<1],first[N],tot;
inline void build_line(int uu,int vv)
{
	v[++tot]=vv,nxt[tot]=first[uu];
	first[uu]=tot;return ;
}
inline void dfs(int x,int fa,int depth)
{
	int lin=0;dep[x]=depth;
	while(w[sta[tp]]<=w[x]&&tp>0)
		rb[++rp]=sta[tp--],lin++;
	f[x]=sta[tp];sta[++tp]=x;
	for(rint i=first[x];i;i=nxt[i])
		if(v[i]!=fa)dfs(v[i],x,depth+1);
	tp--;
	while(lin)
	{
		sta[++tp]=rb[rp--];
		lin--;
	}
	return ;
}
int main()
{
//	freopen("data.in","r",stdin);
//	freopen("std.out","w",stdout);
	read(n),read(q);
	for(rint i=1;i<=n;++i)read(w[i]);
	for(rint i=1,ST,EN;i<n;++i)
	{
		read(ST),read(EN);
		build_line(ST,EN);
		build_line(EN,ST);
	}
	w[0]=0x7fffffff;dfs(1,0,1);
	for(rint i=1,ui,vi,ci;i<=q;++i)
	{
		read(ui),read(vi),read(ci);ans=0;
		while(dep[ui]>dep[vi]){if(w[ui]>ci)ci=w[ui],ans++;ui=f[ui];}
		if(w[vi]>ci)ans++;printf("%d\n",ans);
	}
	return 0;
}
相關文章
相關標籤/搜索