[2018.11.05 T3] 零食

暂无链接

零食

题目背景

TomTom最终还是放弃了买牛奶,选择了买零食。

题目描述

由于TomTom是一只有收集癖的猫,他会把很多零食堆在他的窝里面。

TomTom的窝由nn个独立的房间组成,房间与房间之间有n1n−1条过道,且从任意一个独立的房间可以经过过道到达其他所有的房间,TomTom的窝的入口在11号房间处。

由于TomTom买了太多的零食,所以他每次会选择一个房间,携带巨量零食,从猫窝的入口走到这个房间。他会在走过的房间里做上记号,方便等会儿原路返回。(目标房间不会被做上记号)

到达这个目标房间后,TomTom会从这个房间开始,把所有 可以不经过做了记号房间就可以达到的房间 中堆满零食。做完后,他会沿着他放下的记号离开猫窝,并且把这些记号抹去。

JerryJerry听说TomTom买了很多零食,再加上他今天很饿,于是他决定去偷吃一部分。

JerryJerry每次会选择一个房间,从11号房间进入TomTom的窝,然后直接走向那个房间。他会把路上经过的所有房间中的所有零食全部吃掉。

由于Tom and JerryTom\ and\ Jerry有很多集,这样的事情也不可能只发生了一次。

TomTom在多次买来零食后,发现自己的零食仿佛被人吃掉了不少,于是他心生好奇:在我的窝里的某个房间里,现在还有没有零食啊?

请编写一个程序帮TomTom解决这个问题。

一句话题意:

给定一颗nn个点,11号节点为根的树,支持三种操作:

给定子树中所有点的权值赋值为11,从根到某个节点的路径上所有点的权值赋值为00,查询一个点的权值。

输入格式

第一行输入一个整数nn,代表TomTom的窝有nn个房间。

接下来n1n−1行,每行输入两个数字l,rl,r,代表TomTom的窝中,编号为ll的房间与编号为rr的房间之间有一条过道。

下一行输入一个整数QQ,代表接下来有QQ次 有关零食的事件或TomTom的好奇。

接下来QQ行,每行两个数t,kt,k

t=1t=1,则表示TomTom按照上述规则走到了kk号房间,并堆了一波零食。

t=2t=2,则表示JerryJerry光顾了TomTom的窝,从11号房间走到kk号房间,顺便吃掉了路上房间的零食。

t=3t=3,则表示TomTom现在很好奇,kk号房间中还有没有零食。

输出格式

对于每一个t=3t=3,你需要输出一行一个数字。

若房间中有零食,则输出11,否则输出00

输入样例

5
1 2
5 1
2 3
4 2
12
1 1
2 3
3 1
3 2
3 3
3 4
1 2
2 4
3 1
3 3
3 4
3 5

输出样例

0
0
0
1
0
1
0
1

数据范围

对于40%40\%的数据,保证n,Q<=1000n,Q<=1000

对于70%70\%的数据,保证n,Q<=100000n,Q<=100000

对于100%100\%的数据,保证n,Q<=500000n,Q<=500000

出题人会尽力卡掉Q×Log2(n)Q×Log^2(n)的同学

题解

子树操作的话用线段树+dfsdfs序就可以了,点到根的路径的话有点奇妙,因为点到根的路径与子树是互逆的关系,我们把赋值为00的标记打到链的最底端,子树赋值为11时查询自己子树内有没有00,如果有的话就把标记扔到自己父亲那儿,然后区间赋值即可,查询同理。

代码
#include<bits/stdc++.h>
#define add(a,b) nxt[++cnt]=head[a],head[a]=cnt,to[cnt]=b
#define ls v<<1
#define rs ls|1
using namespace std;
const int M=5e5+5;
int head[M],nxt[M<<1],to[M<<1],dfn[M],dad[M],ri[M],n,m,cnt,df;
bool all[M<<2],tag[M<<2];
void dfs(int v,int f){dfn[v]=++df,dad[v]=f;for(int i=head[v];i;i=nxt[i])if(to[i]!=f)dfs(to[i],v);ri[v]=df;}
void up(int v){all[v]=all[ls]&all[rs];}
void push(int v){if(tag[v])all[ls]=tag[ls]=all[rs]=tag[rs]=1;tag[v]=0;}
bool ask(int v,int l,int r,int lb,int rb)
{
	if(lb<=l&&r<=rb)return all[v];
	int mid=l+r>>1,ans=1;push(v);
	if(lb<=mid)ans=ask(ls,l,mid,lb,rb);
	if(mid<rb)ans&=ask(rs,mid+1,r,lb,rb);
	up(v);return ans;
}
void modi(int v,int l,int r,int lb,int rb)
{
	if(lb<=l&&r<=rb){tag[v]=all[v]=1;return;}
	int mid=l+r>>1;
	if(lb<=mid)modi(ls,l,mid,lb,rb);
	if(mid<rb)modi(rs,mid+1,r,lb,rb);
}
void modi(int v,int l,int r,int pos)
{
	if(l==r){all[v]=0;return;}
	int mid=l+r>>1;push(v);
	if(pos<=mid)modi(ls,l,mid,pos);
	else modi(rs,mid+1,r,pos);
	up(v);
}
void in(){scanf("%d",&n);for(int i=1,a,b;i<n;++i)scanf("%d%d",&a,&b),add(a,b),add(b,a);}
void ac()
{
	dfs(1,0);scanf("%d",&m);
	for(int op,a;m--;)
	{
		scanf("%d%d",&op,&a);
		if(op==1){if(!ask(1,1,n,dfn[a],ri[a]))modi(1,1,n,dfn[dad[a]]);modi(1,1,n,dfn[a],ri[a]);}
		else if(op==2)modi(1,1,n,dfn[a]);
		else printf("%d\n",ask(1,1,n,dfn[a],ri[a]));
	}
}
int main(){in(),ac();}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章