[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();}

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