[HAOI2016]地图

题意

题目

做法

看到还有莫队+分块的神仙,反正我是没有想到的,没想到子树信息还能化成莫队???

首先,这道题目明摆着仙人掌,然后处理子树信息线段树合并即可。

这篇博客主要是记载我这另类的线段树合并的。

这道题目的线段树合并比较奇怪,因为子树信息是可以重合的,甚至还不满足可加性。。。

但是如果你能理解主席树的时间复杂度,你就可以知道这个并不是什么大问题。

时间复杂度:\(O((n+q)logn)\)

空间复杂度:\(O(nlog值域)\)

#include<cstdio>
#include<cstring>
#define  N  110000
#define  NN  210000
#define  SN  6100000
#define  M  320000
using  namespace  std;
inline  int  mymin(int  x,int  y){return  x<y?x:y;}
inline  int  mymax(int  x,int  y){return  x>y?x:y;}
class  EDGE
{
	public:
		struct  node
		{
			int  y,next;
		}a[M];int  len,last[NN];
		void  ins(int  x,int  y){len++;a[len].y=y;a[len].next=last[x];last[x]=len;}
}a1,a2;
struct  node
{
	int  l,r,c1/*奇数次*/,c2/*偶数次*/;
	bool  bk;//我的儿子是否是复制别人的 
}tr[SN];int  len,rt[NN];
inline  void  updata(int  x){tr[x].c1=tr[tr[x].l].c1+tr[tr[x].r].c1;tr[x].c2=tr[tr[x].l].c2+tr[tr[x].r].c2;}
void  link(int  &x,int  l,int  r,int  k)
{
	if(l==r)
	{
		if(!x)x=++len,tr[x].c1=1;
		else  if(tr[x].c1)tr[x].c1=0,tr[x].c2=1;
		else  tr[x].c1=1,tr[x].c2=0;
		return  ;
	}
	if(!x)x=++len;
	int  mid=(l+r)>>1;
	if(k<=mid)link(tr[x].l,l,mid,k);
	else  link(tr[x].r,mid+1,r,k);
	updata(x);
}
void  merge(int  &x,int  &y,int  l,int  r,int  dep)//另类合并 
{
	if(!y)return  ;
	else  if(!x)
	{
		x=++len;
		tr[x]=tr[y];
		tr[x].bk=1;//直接等于y,但是修改不能直接修改,会改变子树的信息
		return  ;
	}
	if(l==r)
	{
		int  tx=0,ty=0;
		if(tr[x].c1==1)tx=1;
		if(tr[y].c1==1)ty=1;
		if((tx+ty)&1)tr[x].c1=1,tr[x].c2=0;
		else  tr[x].c2=1,tr[x].c1=0;
		return  ;
	}
	if(tr[x].bk==1)//不难证明,这样子产生的点数为nlogn
	{
		int  lc=0,rc=0;
		if(tr[x].l)tr[lc=++len]=tr[tr[x].l],tr[lc].bk=1;
		if(tr[x].r)tr[rc=++len]=tr[tr[x].r],tr[rc].bk=1;
		//之前我直接创两个儿子节点是不行的,因为这样原本为空的儿子节点就变成可实实在在的儿子节点了。
		tr[x].l=lc;tr[x].r=rc;
		tr[x].bk=0;
	}
	int  mid=(l+r)>>1;
	merge(tr[x].l,tr[y].l,l,mid,dep+1);merge(tr[x].r,tr[y].r,mid+1,r,dep+1);
	updata(x);
}
int  findans(int  x,int  l,int  r,int  k,int  type)
{
	if(!x)return  0;
	if(r<=k)return  type==0?tr[x].c2:tr[x].c1;
	int  mid=(l+r)>>1;
	if(mid>=k)return  findans(tr[x].l,l,mid,k,type);
	else  return  findans(tr[x].l,l,mid,k,type)+findans(tr[x].r,mid+1,r,k,type);
}
int  dfn[N],low[N],sta[N],top,cnt,n,m,ti;
void  dfs1(int  x)
{
	sta[++top]=x;dfn[x]=low[x]=++ti;
	for(int  k=a1.last[x];k;k=a1.a[k].next)
	{
		int  y=a1.a[k].y;
		if(!dfn[y])
		{
			dfs1(y);
			low[x]=mymin(low[y],low[x]);
			if(low[y]==dfn[x])
			{
				cnt++;
				while(sta[top]!=y)a2.ins(n+cnt,sta[top--]);
				a2.ins(n+cnt,sta[top--]);
				a2.ins(x,n+cnt);
			}
		}
		else  low[x]=mymin(low[x],dfn[y]);
	}
}
int  fa[NN],val[N];
void  dfs2(int  x)
{
	if(x<=n)link(rt[x],1,val[0],val[x]);
	for(int  k=a2.last[x];k;k=a2.a[k].next)
	{
		int  y=a2.a[k].y;
		if(y!=fa[x])
		{
			fa[y]=x;
			dfs2(y);
			merge(rt[x],rt[y],1,val[0],0);
		}
	}
}
int  main()
{
	scanf("%d%d",&n,&m);
	for(int  i=1;i<=n;i++){scanf("%d",&val[i]);val[0]=mymax(val[i],val[0]);}
	for(int  i=1;i<=m;i++)
	{
		int  x,y;scanf("%d%d",&x,&y);
		a1.ins(x,y);a1.ins(y,x);
	}
	dfs1(1);
	dfs2(1);
	int  q;scanf("%d",&q);
	for(int  i=1;i<=q;i++)
	{
		int  id,type,limit;scanf("%d%d%d",&type,&id,&limit);
		printf("%d\n",findans(rt[id],1,val[0],limit,type));
	}
	return  0;
}
posted @ 2020-10-29 08:55  敌敌畏58  阅读(80)  评论(0编辑  收藏  举报