Ynoi2016 这是我自己发明的

Posted yspm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ynoi2016 这是我自己发明的相关的知识,希望对你有一定的参考价值。

Description

link

支持换根和给定两个点,求子树中满足权值相同的方案数

Solution

遥远的国度 (+) 一个简单的询问

(上面两个都是题目名称)

推荐卡常数技巧:把没有用的询问都删掉(就是(l_1,l_2)(1)(0) 比关系的时候)

别的不用stl或者不用函数,手写一类的不大好使(蒟蒻的个人经历)

Code

#include<bits/stdc++.h>
using namespace std;
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k==‘-‘) f=-1;
		while(isdigit(k)) res=res*10+k-‘0‘,k=getchar();
		return res*f;
	}
	const int N=5e5+10;
	int a[N],b[N],m,n,T,bl[N],fa[N][25],dep[N],st[N],ed[N],head[N],cnt,tot,dfn,block,ans[N*5],p[N];
	struct node{
		int nxt,to;
	}e[N<<1];
	inline void add(int u,int v)
	{
		e[++cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt;
		return ;
	}
	inline void dfs(int x,int fat)
	{
		dep[x]=dep[fat]+1; st[x]=++dfn; fa[x][0]=fat; p[dfn]=x;
		for(int i=1;(1<<i)<=dep[x];++i) fa[x][i]=fa[fa[x][i-1]][i-1];
		for(int i=head[x];i;i=e[i].nxt) if(e[i].to==fat) continue; else dfs(e[i].to,x);
		ed[x]=dfn;
		return ;
	}
	struct ask{
		int l,r,fl,id;
		inline void init(int a,int b,int c,int d){l=a,r=b,fl=c,id=d; return ;}
		bool operator <(const ask &x) const
		{
			if(bl[l]!=bl[x.l]) return l<x.l;
			if(bl[l]&1) return r<x.r;
			return r>x.r;
		}
	}q[N*16];
	int res,l=0,r=0,s1[N],s2[N],opt,rt=1,num;
	inline void add1(int x)
	{
		s1[x]++; res+=s2[x];
		return ;
	}
	inline void del1(int x)
	{
		s1[x]--; res-=s2[x];
		return ;
	}
	inline void del2(int x)
	{
		s2[x]--; res-=s1[x];
		return ;
	}
	inline void add2(int x)
	{
		s2[x]++; res+=s1[x];
		return ;
	}
	int t1[10],t2[10],now,sz,x,y;
	inline void calc(int x)
	{
		if(x==rt) 
		{
			t1[++now]=1,t2[now]=n;
		}
		else if(!(st[x]<=st[rt]&&ed[rt]<=ed[x])) 
		{
			t1[++now]=st[x]; t2[now]=ed[x];
		}
		else
		{
			int p=dep[rt]-dep[x]-1,y=rt;
			for(int i=0;i<18;++i) 
			{
				if(p&(1<<i)) y=fa[y][i];
			} 
			t1[++now]=1; t2[now]=st[y]-1;
			t1[++now]=ed[y]+1; t2[now]=n;
		}return ;
	}
	#define l1 t1[i]
	#define l2 t1[j]
	#define r1 t2[i]
	#define r2 t2[j]
	signed main()
	{
		n=read(); T=read(); block=sqrt(n);
		for(int i=1;i<=n;++i) bl[i]=(i-1)/block+1,a[i]=read(),b[++m]=a[i];
		sort(b+1,b+m+1); m=unique(b+1,b+m+1)-b-1;
		for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+m+1,a[i])-b;
		for(int i=1,u,v;i<n;++i) u=read(),v=read(),add(u,v),add(v,u);
		dfs(1,0);
		while(T--)
		{
			opt=read();
			if(opt==1) rt=read();
			else
			{
				x=read(),y=read(); ++num; now=0; calc(x); sz=now; calc(y);
				for(int i=1;i<=sz;++i) 
				{
					for(int j=sz+1;j<=now;++j) 
					{
						if(l1>r1||l2>r2||l1<1||l2<1||r2>n||l2>n) continue; 
						if(l1>1&&l2>1) q[++tot].fl=1,q[tot].id=num,q[tot].l=l1-1,q[tot].r=l2-1;
						q[++tot].fl=1; q[tot].id=num; q[tot].l=r1; q[tot].r=r2;
						if(l1>1) q[++tot].fl=-1,q[tot].id=num,q[tot].r=r2,q[tot].l=l1-1;
						if(l2>1) q[++tot].fl=-1,q[tot].id=num,q[tot].r=r1,q[tot].l=l2-1;
					}
				}
			} 
		}
		for(int i=1;i<=tot;++i) if(q[i].l>q[i].r) swap(q[i].l,q[i].r);
		sort(q+1,q+tot+1);
		for(int i=1;i<=tot;++i)
		{
			while(l<q[i].l) ++l,add1(a[p[l]]);
			while(l>q[i].l) del1(a[p[l]]),--l;
			while(r<q[i].r) ++r,add2(a[p[r]]);
			while(r>q[i].r) del2(a[p[r]]),--r;
			ans[q[i].id]+=q[i].fl*res;
		} 
		for(int i=1;i<=num;++i) printf("%d
",ans[i]);
		return 0;
	}
}
signed main(){return yspm::main();}

以上是关于Ynoi2016 这是我自己发明的的主要内容,如果未能解决你的问题,请参考以下文章

「Luogu P4689 [Ynoi2016]这是我自己的发明」

「Luogu P4689 [Ynoi2016]这是我自己的发明」

luogu P4688 [Ynoi2016]掉进兔子洞 bitset 莫队

luogu P4688 [Ynoi2016]掉进兔子洞

题解 P4692 [Ynoi2016]谁的梦

[Ynoi2016]镜中的昆虫