spoj ADAAPPLE - Ada and Apple(树链刨分+线段树)

ADAAPPLE - Ada and Apple

#tree #datastructures

 

Ada the Ladybug is currently on a trip on apple tree. There are many apples on the tree connected with branches. Each apple is inhabited by either Psylloideas or by Woolly Apple Aphids. Psylloideas and Aphids doesn't like each other, so it is strictly prohibited to walk from apple of Psylloideas to apple of aphids (and vice versa). Ada has some questions, whether it is possible to go from node I to node J.

Anyway note, that as Aphids and Psyllodeas doesn't like each other, they sometime conquer an apple of the others. Also note, that it is a real apple tree (not some bush) so no apple is connected with more than 50 other apples.

Input

The first line contains 1 ≤ N, Q ≤ 3*105 , number apples on tree and number for queries.

The next line contains N characters (either 0 or 1), indicating whether ith apple belongs to Psyllodeas or to Aphids.

Next N-1 lines contains two numbers, the branches (edges) of apple tree (0 ≤ I, J < NI ≠ J).

Each of following Q lines contains one of following types of queries:

0 I0 ≤ I < N, meaning that ownership of Ith apple has changed.

1 I J0 ≤ I, J < N, question, whether it is possible to go from Ith to Jth apple.

Output

For each query of second kind (1) print "YES", if it is possible or "NO" if it is impossible!

Example Input

8 11
00111100
0 1
1 7
1 2
2 3
2 6
2 4
4 5
1 1 2
1 0 7
1 6 5
1 2 3
1 6 7
0 2
1 1 2
1 0 7
1 6 5
1 2 3
1 6 7

Example Output

NO
YES
NO
YES
NO
YES
YES
NO
NO
YES

题意:一棵树,点的权值只有0和1两种情况,询问树上两点之间的路径是否全为0或全为1。路径操作很容易想到树链刨分,树链刨分后,形成多段连续区间,用线段树维护查询这些区间即可。

#include<bits/stdc++.h>
#define MAXN 300005
using namespace std; 
int n,q,indx;
int info[MAXN],a[MAXN],nd[MAXN],father[MAXN],dn[MAXN];
vector<int> to,nxt;
struct node{
	int v,left,right;
}tree[4*MAXN];
void addedge(int a,int b)
{
	to.push_back(b);
    nxt.push_back(info[a]);
    info[a]=to.size()-1;
}
void build(int id,int L,int R)
{
    tree[id].left=L,tree[id].right=R;
    if(L==R)
    {
        tree[id].v=a[dn[L]];
        return;
    }
    int mid=(tree[id].left+tree[id].right)/2;
    build(id*2,L,mid);
    build(id*2+1,mid+1,R);
    tree[id].v=tree[id*2].v+tree[id*2+1].v;
}

void update(int id,int pos)
{
    if(tree[id].right==pos&&tree[id].left==pos)
    {
        tree[id].v=1-tree[id].v;
        return;
    }
    int mid=(tree[id].left+tree[id].right)/2;
    if(pos<=mid)
        update(id*2,pos);
    else if(pos>mid)
        update(id*2+1,pos);
    tree[id].v=tree[id*2].v+tree[id*2+1].v;
}
int query(int id,int L,int R)
{
    if(tree[id].left==L&&tree[id].right==R)
        return tree[id].v;
    int mid=(tree[id].left+tree[id].right)/2;
    if(mid<L)
        return query(id*2+1,L,R);
    else if(mid>=R)
        return query(id*2,L,R);
    else
    	return query(id*2,L,mid)+query(id*2+1,mid+1,R);
}
int dep[MAXN],heavyson[MAXN],size[MAXN];
void dfs1(int u,int fa)
{
	father[u]=fa;
    dep[u]=dep[fa]+1;
    size[u]=1;
    heavyson[u]=0;
    int mmax=0;
    for(int i=info[u];i!=-1;i=nxt[i])
    {
    	int v=to[i];
    	if(v!=fa)
    	{
    		dfs1(v,u);
    		size[u]+=size[v];
    		if(size[v]>mmax)
    		{
    			heavyson[u]=v;
    			mmax=size[v];
			}
		}
	}
}
int tp[MAXN];
void dfs2(int u,int ance)
{
	nd[u]=++indx;
	dn[indx]=u;
	tp[u]=ance;
    if(heavyson[u]) 
		dfs2(heavyson[u],ance);
	for(int i=info[u];i!=-1;i=nxt[i])
	{
		int v=to[i];
		if(v!=father[u]&&v!=heavyson[u])
			dfs2(v,v);
	}
}
bool ask(int u,int v)
{
    int anceu=tp[u],ancev=tp[v];
    int ans=0,sum=0;
    while(anceu!=ancev)
    {
        if(dep[anceu]<dep[ancev])
        {
        	swap(anceu,ancev);
			swap(u,v);
		}
        sum+=nd[u]-nd[anceu]+1;
        ans+=query(1,nd[anceu],nd[u]);
        u=father[anceu];
        anceu=tp[u];
    }
    if(dep[u]<dep[v])
		swap(u,v);
	sum+=nd[u]-nd[v]+1;
	ans+=query(1,nd[v],nd[u]);
	if(ans==sum||ans==0)
	return true;
	else
	return false;
}

void init()
{
    indx=0;dep[0]=0;
    memset(info,-1,sizeof(info));
    to.clear();
    nxt.clear();
}
int main()
{
	int n,q;
	scanf("%d%d",&n,&q);
	getchar();
	for(int i=1;i<=n;i++)
	{
		char c=getchar();
		a[i]=c-'0';
	}
    getchar();
    init();
    for(int i=0;i<n-1;i++)
    {
    	int u,v;
    	scanf("%d%d",&u,&v);
    	addedge(u+1,v+1);
    	addedge(v+1,u+1);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	for(int i=0;i<q;i++)
	{
		int op,x,y;
		scanf("%d",&op);
		if(op==0)
		{
			scanf("%d",&x);
			a[x+1]=1-a[x+1];
			update(1,nd[x+1]);
		}
		else
		{
			scanf("%d%d",&x,&y);
			if(ask(x+1,y+1))
				printf("YES\n");
			else
				printf("NO\n");
		}		
	}
	return 0;    
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值