P5838 [USACO19DEC]Milk Visits G(树剖性质妙用)

P5838 [USACO19DEC]Milk Visits G

看似要用LCA来写,但是并不需要

考虑树剖的重要性质,重链上时间戳连续,那么就可以按照时间戳的顺序建主席树,无脑的查就行了

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#define inf 0x7fffffff
#define ll long long
//#define int long long
//#define double long double
#define re int
#define void inline void
#define eps 1e-5
//#define mod 1e9+7
//#define ls(p) p<<1
//#define rs(p) p<<1|1
//#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
#define fi first
#define se second
#define unordered_map map
//#define __int128 long long
using namespace std;
using namespace __gnu_pbds;
const int M=1e5+5;
const int mod=1e9;
const int N=2e5+5;
int n,m,a[N];
int s[N],tp;
namespace HJT
{
	#define ls(p)  e[p].l
	#define rs(p)  e[p].r
	struct node
	{
		int l,r,sum;
	}e[N*40];
	int rt[N],tot;
	void insert(int &p,int pre,int l,int r,int pos)
	{
		p=++tot;
		e[p]=e[pre];
		e[p].sum++;
		if(l==r)  return;
		int mid=(l+r)>>1;
		if(pos<=mid)  insert(ls(p),ls(pre),l,mid,pos);
		else  insert(rs(p),rs(pre),mid+1,r,pos);
	}
	int ask(int L,int R,int l,int r,int pos)
	{
		if(l==r)  return e[R].sum-e[L].sum;
		int mid=(l+r)>>1;
		if(pos<=mid)  return ask(ls(L),ls(R),l,mid,pos);
		return ask(rs(L),rs(R),mid+1,r,pos);
	}
}
namespace GP
{
	using namespace HJT;
	struct nod
	{
		int ver,next;
	}e[N];
	int tot,head[N];
	int num,sz[N],top[N],fa[N],son[N],dfn[N],w[N],d[N];
	void add(int x,int y)
	{
		e[++tot].ver=y;
		e[tot].next=head[x];
		head[x]=tot;
	}
	void addedge(int x,int y)
	{
		add(x,y);add(y,x);
	}
	void dfs1(int x,int pre)
	{
		sz[x]=1,fa[x]=pre,d[x]=d[pre]+1;
		int ma=-1;
		for(re i=head[x];i;i=e[i].next)
		{
			int y=e[i].ver;
			if(y==pre)  continue;
			dfs1(y,x);
			sz[x]+=sz[y];
			if(ma<sz[y])  ma=sz[y],son[x]=y;
		}
	}
	void dfs2(int x,int pre)
	{
		top[x]=pre;dfn[x]=++num;
		w[num]=a[x];
		if(!son[x])  return;
		dfs2(son[x],pre);
		for(re i=head[x];i;i=e[i].next)
		{
			int y=e[i].ver;
			if(y==son[x]||y==fa[x])  continue;
			dfs2(y,y);
		}
	}
	void bulid()
	{
		for(re i=1;i<=n;i++)  insert(rt[i],rt[i-1],1,n,w[i]);
	}
	void query(int x,int y,int op)
	{
		int z=0,ans=0;
		while(top[x]!=top[y])
		{
			if(d[top[x]]<d[top[y]])  swap(x,y);
			ans=ask(rt[dfn[top[x]]-1],rt[dfn[x]],1,n,op);
			if(ans)  z=1;
			x=fa[top[x]];
		}
		if(d[x]>d[y])  swap(x,y);
		ans=ask(rt[dfn[x]-1],rt[dfn[y]],1,n,op);
		if(ans)  z=1;
		s[++tp]=z;
	}
}
void solve()
{
	cin>>n>>m;
	for(re i=1;i<=n;i++)  scanf("%d",&a[i]);
	for(re i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		GP::addedge(x,y);
	}
	GP::dfs1(1,1);GP::dfs2(1,1);
	GP::bulid();
	for(re i=1;i<=m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		GP::query(x,y,z);
	}
	for(re i=1;i<=m;i++)  printf("%d",s[i]);puts("");
}
signed main()
{
//	fflush(stdout);
//	srand(102321547);
//	freopen("D.in", "r", stdin);
//	freopen("D2.out", "w", stdout);
//	freopen("9.out", "w", stdout);
    int T=1;
//    cin>>T;
    for(re index=1;index<=T;index++)
    {
//        printf("Case #%d:\n",index);
        solve();
//        puts("");
    }
    return 0;
}
/*

1 4
3 4
15 38 45 52 59 36




*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值