樹上詢問

D06發表於2024-08-22
  • 對於路徑操作,DFS序是不可做的,可以考慮尤拉序
  • 尤拉序:對一棵樹進行DFS,無論是第一次訪問還是回溯,每次到達一個結點時都將編號記錄下來,長度為2(n-1)+1=2n-1,每條邊都被訪問兩次
  • 在LCA問題中,可以透過尤拉序將其轉化為RMQ問題
  • 於是,[l,r]內DFS序最大的節點為路徑的一個端點
  • 考慮記錄下每個節點尤拉序最後出現的位置,那麼,這個位置最小(向上走)或最大(向下走)的節點為路徑的另一個端點
  • 從另一個角度考慮,區間的兩個端點之間距離最大
  • 問題轉化為:怎樣維護路徑[x,y]內的某些資訊,以判斷題目中的條件是否成立,這或許就是【資訊學奧賽】的精髓所在
  • 用最大最小值夾逼,再結合路徑長度即可判斷
  • 好感動,手寫1個半小時6KB程式碼,寫完一部分程式碼就除錯一下,最終一次透過了大樣例
點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
vector<int>a[100005];
int p[100005],n;
int dfn[100005],e[200005],tot,cnt,s[100005],z[100005],id[100005],h[100005],w[100005],d[100005],fa[100005],raw[100005],pos[100005];
struct t1
{
	int l,r,minn,maxn;
}t[400005];
struct f1
{
	int l,r,dfn,pos1,pos2;
}f[400005];
void buildt(int p,int l,int r)
{
	t[p].l=l;
	t[p].r=r;
	if(l==r)
	{
		t[p].minn=t[p].maxn=w[l];
		return;
	}
	int mid=(l+r)>>1;
	buildt(p*2,l,mid);
	buildt(p*2+1,mid+1,r);
	t[p].minn=min(t[p*2].minn,t[p*2+1].minn);
	t[p].maxn=max(t[p*2].maxn,t[p*2+1].maxn);
}
void buildf(int p,int l,int r)
{
	f[p].l=l;
	f[p].r=r;
	if(l==r)
	{
		f[p].dfn=f[p].pos1=f[p].pos2=raw[l];
		return;
	}
	int mid=(l+r)>>1;
	buildf(p*2,l,mid);
	buildf(p*2+1,mid+1,r);
	f[p].dfn=(dfn[f[p*2].dfn]>dfn[f[p*2+1].dfn])*f[p*2].dfn+(dfn[f[p*2].dfn]<dfn[f[p*2+1].dfn])*f[p*2+1].dfn;
	f[p].pos1=(pos[f[p*2].pos1]<pos[f[p*2+1].pos1])*f[p*2].pos1+(pos[f[p*2].pos1]>pos[f[p*2+1].pos1])*f[p*2+1].pos1;
	f[p].pos2=(pos[f[p*2].pos2]>pos[f[p*2+1].pos2])*f[p*2].pos2+(pos[f[p*2].pos2]<pos[f[p*2+1].pos2])*f[p*2+1].pos2;
}
void changef(int p,int x)
{
	if(f[p].l==f[p].r)
	{
		f[p].dfn=f[p].pos1=f[p].pos2=raw[x];
		return;
	}
	int mid=(f[p].l+f[p].r)>>1;
	if(x<=mid)
	{
		changef(p*2,x);
	}
	else
	{
		changef(p*2+1,x);
	}
	f[p].dfn=(dfn[f[p*2].dfn]>dfn[f[p*2+1].dfn])*f[p*2].dfn+(dfn[f[p*2].dfn]<dfn[f[p*2+1].dfn])*f[p*2+1].dfn;
	f[p].pos1=(pos[f[p*2].pos1]<pos[f[p*2+1].pos1])*f[p*2].pos1+(pos[f[p*2].pos1]>pos[f[p*2+1].pos1])*f[p*2+1].pos1;
	f[p].pos2=(pos[f[p*2].pos2]>pos[f[p*2+1].pos2])*f[p*2].pos2+(pos[f[p*2].pos2]<pos[f[p*2+1].pos2])*f[p*2+1].pos2;
}
void changet(int p,int x,int va)
{
	if(t[p].l==t[p].r)
	{
		t[p].minn=t[p].maxn=va;
		return;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(x<=mid)
	{
		changet(p*2,x,va);
	}
	else
	{
		changet(p*2+1,x,va);
	}
	t[p].minn=min(t[p*2].minn,t[p*2+1].minn);
	t[p].maxn=max(t[p*2].maxn,t[p*2+1].maxn);
}
int askminn(int p,int l,int r)
{
	if(l<=t[p].l&&r>=t[p].r)
	{
		return t[p].minn;
	}
	int mid=(t[p].l+t[p].r)>>1,va=INT_MAX;
	if(l<=mid)
	{
		va=min(va,askminn(p*2,l,r));
	}
	if(r>mid)
	{
		va=min(va,askminn(p*2+1,l,r));
	}
	return va;
}
int askmaxn(int p,int l,int r)
{
	if(l<=t[p].l&&r>=t[p].r)
	{
		return t[p].maxn;
	}
	int mid=(t[p].l+t[p].r)>>1,va=0;
	if(l<=mid)
	{
		va=max(va,askmaxn(p*2,l,r));
	}
	if(r>mid)
	{
		va=max(va,askmaxn(p*2+1,l,r));
	}
	return va;
}
int askdfn(int p,int l,int r)
{
	if(l<=f[p].l&&r>=f[p].r)
	{
		return f[p].dfn;
	}
	int mid=(f[p].l+f[p].r)>>1,va=0;
	if(l<=mid)
	{
		va=askdfn(p*2,l,r);
	}
	if(r>mid)
	{
		if(!va)
		{
			va=askdfn(p*2+1,l,r);
		}
		else
		{
			int tmp=askdfn(p*2+1,l,r);
			if(dfn[va]<dfn[tmp])
			{
				va=tmp;
			}
		}
	}
	return va;
}
int askpos1(int p,int l,int r)
{
	if(l<=f[p].l&&r>=f[p].r)
	{
		return f[p].pos1;
	}
	int mid=(f[p].l+f[p].r)>>1,va=0;
	if(l<=mid)
	{
		va=askpos1(p*2,l,r);
	}
	if(r>mid)
	{
		if(!va)
		{
			va=askpos1(p*2+1,l,r);
		}
		else
		{
			int tmp=askpos1(p*2+1,l,r);
			if(pos[va]>pos[tmp])
			{
				va=tmp;
			}
		}
	}
	return va;
}
int askpos2(int p,int l,int r)
{
	if(l<=f[p].l&&r>=f[p].r)
	{
		return f[p].pos2;
	}
	int mid=(f[p].l+f[p].r)>>1,va=0;
	if(l<=mid)
	{
		va=askpos2(p*2,l,r);
	}
	if(r>mid)
	{
		if(!va)
		{
			va=askpos2(p*2+1,l,r);
		}
		else
		{
			int tmp=askpos2(p*2+1,l,r);
			if(pos[va]<pos[tmp])
			{
				va=tmp;
			}
		}
	}
	return va;
}
void dfs1(int n1)
{
	s[n1]=1;
	dfn[n1]=++tot;
	e[++cnt]=n1;
	z[n1]=0;
	for(int i=0;i<a[n1].size();i++)
	{
		if(a[n1][i]!=fa[n1])
		{
			d[a[n1][i]]=d[n1]+1;
			fa[a[n1][i]]=n1;
			dfs1(a[n1][i]);
			e[++cnt]=n1;
			s[n1]+=s[a[n1][i]];
			if(s[a[n1][i]]>s[z[n1]])
			{
				z[n1]=a[n1][i];
			}
		}
	}
}
void dfs2(int n1)
{
	id[n1]=++tot;
	w[tot]=p[n1];
	if(z[n1])
	{
		h[z[n1]]=h[n1];
		dfs2(z[n1]);
	}
	for(int i=0;i<a[n1].size();i++)
	{
		if(a[n1][i]!=fa[n1]&&a[n1][i]!=z[n1])
		{
			h[a[n1][i]]=a[n1][i];
			dfs2(a[n1][i]);
		}
	}
}
int getminn(int u,int v)
{
	int minn=INT_MAX;
	while(h[u]!=h[v])
	{
		if(d[h[u]]<d[h[v]])
		{
			swap(u,v);
		}
		minn=min(minn,askminn(1,id[h[u]],id[u]));
		u=fa[h[u]];
	}
	minn=min(minn,askminn(1,min(id[u],id[v]),max(id[u],id[v])));
	return minn;
}
int getmaxn(int u,int v)
{
	int maxn=0;
	while(h[u]!=h[v])
	{
		if(d[h[u]]<d[h[v]])
		{
			swap(u,v);
		}
		maxn=max(maxn,askmaxn(1,id[h[u]],id[u]));
		u=fa[h[u]];
	}
	maxn=max(maxn,askmaxn(1,min(id[u],id[v]),max(id[u],id[v])));
	return maxn;
}
int getlen(int u,int v)
{
	int len=0;
	while(h[u]!=h[v])
	{
		if(d[h[u]]<d[h[v]])
		{
			swap(u,v);
		}
		len=len+d[u]-d[fa[h[u]]];
		u=fa[h[u]];
	}
	len=len+abs(d[u]-d[v]);
	return len;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			a[i].clear();
			cin>>p[i];
			raw[p[i]]=i;
		}
		for(int i=1;i<n;i++)
		{
			int u,v;
			cin>>u>>v;
			a[u].push_back(v);
			a[v].push_back(u);
		}
		cnt=tot=0;
		d[1]=1;
		fa[1]=0;
		dfs1(1);
		tot=0;
		dfs2(1);
		for(int i=1;i<=cnt;i++)
		{
			pos[e[i]]=i;
		}
		buildt(1,1,n);
		buildf(1,1,n);
		int m;
		cin>>m;
		for(int i=1;i<=m;i++)
		{
			int opt,u,v;
			cin>>opt>>u>>v;
			if(opt==1)
			{
				changet(1,id[u],w[id[v]]);
				changet(1,id[v],w[id[u]]);
				swap(w[id[u]],w[id[v]]);
				raw[p[u]]=v;
				changef(1,p[u]);
				raw[p[v]]=u;
				changef(1,p[v]);
				swap(p[u],p[v]);
			}
			else
			{
				int x=askpos1(1,u,v);
				int y=askdfn(1,u,v);
				if(x==y)
				{
					x=askpos2(1,u,v);
				}
				int len=getlen(x,y);
				if(len==v-u&&getmaxn(x,y)==v&&getminn(x,y)==u)
				{
					cout<<"Yes"<<"\n";
				}
				else
				{
					cout<<"No"<<"\n";
				}
			}
		}
	}
	return 0;
}
/*
1
9
3 4 9 5 1 2 7 6 8
1 2
2 3
2 4
2 5
1 6
6 7
7 8
7 9
*/

相關文章