zl程序教程

您现在的位置是:首页 >  其它

当前栏目

[2018.11.05 T3] 零食

05 T3
2023-09-27 14:28:32 时间

暂无链接

零食

题目背景

T o m Tom Tom最终还是放弃了买牛奶,选择了买零食。

题目描述

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

T o m Tom Tom的窝由 n n n个独立的房间组成,房间与房间之间有 n − 1 n−1 n1条过道,且从任意一个独立的房间可以经过过道到达其他所有的房间, T o m Tom Tom的窝的入口在 1 1 1号房间处。

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

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

J e r r y Jerry Jerry听说 T o m Tom Tom买了很多零食,再加上他今天很饿,于是他决定去偷吃一部分。

J e r r y Jerry Jerry每次会选择一个房间,从 1 1 1号房间进入 T o m Tom Tom的窝,然后直接走向那个房间。他会把路上经过的所有房间中的所有零食全部吃掉。

由于 T o m   a n d   J e r r y Tom\ and\ Jerry Tom and Jerry有很多集,这样的事情也不可能只发生了一次。

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

请编写一个程序帮 T o m Tom Tom解决这个问题。

一句话题意:

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

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

输入格式

第一行输入一个整数 n n n,代表 T o m Tom Tom的窝有 n n n个房间。

接下来 n − 1 n−1 n1行,每行输入两个数字 l , r l,r l,r,代表 T o m Tom Tom的窝中,编号为 l l l的房间与编号为 r r r的房间之间有一条过道。

下一行输入一个整数 Q Q Q,代表接下来有 Q Q Q次 有关零食的事件或 T o m Tom Tom的好奇。

接下来 Q Q Q行,每行两个数 t , k t,k t,k

t = 1 t=1 t=1,则表示 T o m Tom Tom按照上述规则走到了 k k k号房间,并堆了一波零食。

t = 2 t=2 t=2,则表示 J e r r y Jerry Jerry光顾了 T o m Tom Tom的窝,从 1 1 1号房间走到 k k k号房间,顺便吃掉了路上房间的零食。

t = 3 t=3 t=3,则表示 T o m Tom Tom现在很好奇, k k k号房间中还有没有零食。

输出格式

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

若房间中有零食,则输出 1 1 1,否则输出 0 0 0

输入样例

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\% 40%的数据,保证 n , Q &lt; = 1000 n,Q&lt;=1000 n,Q<=1000

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

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

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

题解

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

代码
#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();}