首页 > 其他分享 >树上询问

树上询问

时间:2024-08-22 23:47:57浏览次数:8  
标签:va int 询问 pos 100005 dfn 树上 pos2

  • 对于路径操作,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
*/

标签:va,int,询问,pos,100005,dfn,树上,pos2
From: https://www.cnblogs.com/watersail/p/18374767

相关文章

  • P4216[SCOI2015情报传递 树上主席树
    题意:维护一棵树,某些点有点权(没有则为正无穷),点权为正整数,查询树上路径点权小于等于某个值的点的个数。分析:考虑维护主席树,root[i]数组存储第i个节点到根的点权的权值线段树的树根。更具体地,把第i个节点到根的路径上的点权累积到权值线段树中,对一个询问x,y,记lca为z,查询值为k,答案a......
  • 【题解】Solution Set - NOIP2024集训Day12 树上启发式合并
    【题解】SolutionSet-NOIP2024集训Day12树上启发式合并https://www.becoder.com.cn/contest/5472「CF600E」Lomsatgelral直接dsuontree。记录每一个颜色的出现次数。「IOI2011」Race之前是用点分治做的。考虑dsuontree。每个子树内维护到根节点的距离为\(x\)......
  • 树上游戏(树类型题目思考题)
    第2题   树上游戏 查看测评数据信息有一棵n个节点的树。T站在u号节点上,A站在v号节点上。现在,两个人轮流移动,T是先手。每人每次移动必须移动到任何一个相邻的节点。如果某个人发现自己与对方站在了同一个节点上,那么宣布游戏结束。注意每个人每一轮必须移动。已知T希望游戏......
  • lg树上操作
    lg树上操作P3258树上差分P1600[NOIP2016]天天爱跑步分开两边处理。对于上升段,如果一个点深度是x=dep_i+w_i,那么i就被贡献我们可以将整个上升段的x位置都加,然后在每个点处统计dep_i+w_i位置的值。每个点开一个vector记录修改操作。不过这样可能会有互相影响......
  • 树上合并 目前的总结
    启发式合并(set)元素少的set中的元素一一插入元素多的set中。时间两只\(\log\)。空间最坏为\(n\)这个级别(结点数)(这是在默认一个结点最多增加一个元素的情况下)。log数据结构时间也是两只\(\log\)。dsuontree好像[也叫“树上启发式合并”](??)。[一般](?)是重链剖分一样划分......
  • P4689 [Ynoi2016] 这是我自己的发明 与 P5268 [SNOI2017] 一个简单的询问0
    思路:首先可以先考虑没有换根的情况。先将树拍到dfn序上,那么一个子树\(u\)的所有点的dfn序区间为\([dfn_u,dfn_u+siz_u-1]\)。那么询问变为:每次给定两个区间\([l_1,r_1],[l_2,r_2]\),对于在第一个区间内的点\(x\)和在第二个区间的点\(y\),若\((x,y)\)有贡献,当且仅......
  • C240817D. 模拟赛:树上dp(以i为起点)+set操作
    C240817D.模拟赛比较显然的树上dp,但是维护set比较烦考场上其实自己是定义\(f[i]\)是以\(i\)结尾,然后这样的话单次更新根本做不到\(O(logN)\).反应实在是太迟钝了,考场想“如果有一种只更新一条链的dp就好了”结果完全没想到只需变成以\(i\)开头就行了.积累经验吧。......
  • 树上计数2
    树上莫队通过将树转化成DFS序(欧拉序)来解决问题。这道题目跟“HH的项链”很像,考虑树上莫队首先对树做出一个欧拉序,得到每个点在欧拉序中第一次出现的位置in[x]和第二次出现的位置out[x];如果某个询问的\((x,y)\)的in[x]比in[y]大,那么交换\(x,y\),下面假设in[x]比in[y]小如果\(x,y\)......
  • 2024杭电多校第十场 1002树上询问(题解)
    题意给一棵树,每个节点有一个权值,并且权值是一个排列。接下来有多次操作,每次操作要么是交换两个节点权值,要么是询问一个权值区间\([L,R]\),判断是否存在树上的一个路径,使得路径上的权值恰好都在这个区间里分析由于询问的是树上的一个路径,联想到了树上莫队中对路径的处理。这里......
  • 询问(构造,一种新思路)
    第5题   询问 查看测评数据信息给一个长度为n的正整数数组a[1,2,...n],一个长度为m的查询数组q[1,2,...m],q[i]=(val,minlen,maxlen)。请你按输入顺序处理这m次查询,对于第i次查询q[i[=(val,minlen,maxlen);请你输出是否存在一个a的子数组s满足min(s)≥val且s的长度在minlen......