DTOJ#5214. 第一題

csdnzhanghongyu發表於2020-12-02

傳送門
w 國非常的窮,因此在它們國家的 n n n 座城市之間,只有 n − 1 n − 1 n1 條道路使得它們連通。

而就在某一天,新型病毒在 w 國悄無聲息的爆發了。

w 國的領導人小 w 得知訊息之後,決定直接封城以抵抗病毒,然而她萬萬沒有想到的是,這種病毒的傳染能力,異常強大,以至於只需要一個小時,就可以從一個沒有封城的有病例的城市傳播到另外一個沒有封城的相鄰城市,使其市民出現感染病例(注意!在這個小時內新出現病例的城市不會繼續傳播)。作為 w 國的領導人,小 w 在有時會將一些城市封鎖,但是有一些封城城市收到了大量市民的抵抗,無奈解封。小 w 則會時不時想知道一座城市是否已經出現感染病例了。而你,作為小 w 的頂級助理,則要幫助小 w 完成這個任務。

第一行三個正整數 n , m , q n, m, q n,m,q 表示 w w w 國有 n n n 座城市,其中有 m m m 個城市已經感染病毒,並且下面發生了 q q q 個事件。

下面 n − 1 n − 1 n1 行,每行兩個正整數 x i , y i x_i, y_i xi,yi 表示城市 x i x_i xi y i y_i yi 之間有一條道路。

下面一行 m m m 個正整數 a i a_i ai ,表示一開始就已經感染了病毒的城市。

下面 q q q 行,每行第一個正整數 o p t i opt_i opti 表示操作的型別。

o p t i = 1 opt_i = 1 opti=1 ,那麼下面緊跟一個正整數 w w j i wwj_i wwji ,表示城市 w w j i wwj_i wwji 封城了,保證其之前處於未封城的狀態。

o p t i = 2 opt_i = 2 opti=2 ,那麼下面緊跟一個正整數 w w j i wwj_i wwji ,表示城市 w w j i wwj_i wwji 解封了,保證其之前處於封城的狀態。

o p t i = 3 opt_i = 3 opti=3 ,那麼下面緊跟一個正整數 w w j i wwj_i wwji ,表示詢問城市 w w j i wwj_i wwji 是否已經有感染病例。

o p t i = 4 opt_i = 4 opti=4 ,那麼表示過去了一個小時,病毒開始了一輪傳染。

一共若干行,對於一個詢問,如果答案是已經出現病例,那麼輸出 Y,否則輸出 N

樣例輸入

5 1 6
1 2
2 3
3 4
2 5
4
3 4
4
4
3 1
1 1
3 2

樣例輸出

Y
N
Y
Subtask 編號分值性質
1 1 1 1 1 1 o p t i ≠ 3 opt_i \neq 3 opti=3
2 2 2 23 23 23 1 ≤ n , q ≤ 2000 1 \leq n, q \leq 2000 1n,q2000
3 3 3 10 10 10 x i = 1 x_i = 1 xi=1
4 4 4 20 20 20 x i + 1 = y i x_i + 1 = y_i xi+1=yi
5 5 5 13 13 13 m = a i = 1 m = a_i = 1 m=ai=1
6 6 6 21 21 21 1 ≤ n , m , q ≤ 100000 1 \leq n, m, q \leq 100000 1n,m,q100000
7 7 7 12 12 12沒有特殊限制

對於所有資料,保證:

1 ≤ n , m , q ≤ 500000 1 \leq n, m, q \leq 500000 1n,m,q500000

1 ≤ x i , y i ≤ n 1 \leq x_i, y_i \leq n 1xi,yin ,保證圖是連通的。

1 ≤ a i ≤ n 1 \leq a_i \leq n 1ain ,保證 a i a_i ai 互不相同。

1 ≤ o p t i ≤ 4 , 1 ≤ w w j i ≤ n 1 \leq opt_i \leq 4, 1 \leq wwj_i \leq n 1opti4,1wwjin

首先,不得不感嘆我思路新奇。啥都能根號。
首先根號做法即對於修改,度數 < n <\sqrt n <n 的直接修改,度數 > n >\sqrt n >n 的儲存自上次封城後的所有城市,每次解封時全部跑一遍,然後清空。總時間複雜度為 O ( n n ) O(n\sqrt n) O(nn )

#include<bits/stdc++.h>
#define N 500005
using namespace std;
inline char GET_CHAR ( void )
{
    static char buf[1<<23],*p1=buf,*p2=buf;
    return p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2) ? EOF : *p1++;
}
inline int read ( void )
{
	int x=0;char ch;
	while ( !isdigit(ch=GET_CHAR()) ) ;
	for ( x=ch^48;isdigit(ch=GET_CHAR()); ) x=(x<<1)+(x<<3)+(ch^48);
	return x;
}

vector<int> to[N],tmp[710],fa[N],nex;
int sqr,cl[N],is[N],d[N],cnt[N],ht,b[N],pos[N],tim[N],fir[N];
inline void spred(int x,int val){
	if(d[x]<sqr){
		for(int i=0;i<(int)to[x].size();++i){
			int y=to[x][i];
			cnt[y]+=val;
			if(val==1&&is[y]==0&&cl[y]==0&&tim[y]==0){
				//is[y]=1;//cout<<x<<"->"<<y<<endl;
				nex.push_back(y);
			}
		}
	}
}
vector<int> ask;
int main(){
    int n=read(),m=read(),q=read();
    sqr=sqrt(n);
    for(int i=1;i<n;++i){
    	int x=read(),y=read();
    	to[x].push_back(y);to[y].push_back(x);
    	++d[x],++d[y];
    }
    for(int i=1;i<=n;++i)if(d[i]>=sqr)pos[i]=++ht;
    for(int i=1;i<=n;++i){
    	for(int j=0;j<to[i].size();++j){
    		int y=to[i][j];
    		if(pos[y]){
    			fa[i].push_back(y);
    		}
    	}
    }
    for(int i=1;i<=m;++i){
    	int x=read();is[x]=1;
    	ask.push_back(x);tim[x]=1;b[x]=0;
    }
    for(int i=1;i<=n;++i){
    	if(!is[i]){
    		for(int j=0;j<fa[i].size();++j){
    			tmp[pos[fa[i][j]]].push_back(i);
    		}
    	}
    }
    while(q--){
    	int op=read();
    	if(op==1){
    		int x=read();
    		ask.push_back(x);
    		tim[x]=1;
    		b[x]=1;
    	}
    	if(op==2){
    		int x=read();
    		ask.push_back(x);
    		tim[x]=1;
    		b[x]=0;
    	}
    	if(op==3){
    		int x=read();
    		is[x]?putchar('Y'):putchar('N');
    		putchar('\n');
    	}
    	if(op==4){
    		sort(ask.begin(),ask.end());
    		ask.erase(unique(ask.begin(),ask.end()),ask.end());
    		for(int i=0;i<(int)ask.size();++i){
    			int x=ask[i];
    			if(is[x]){
    				if(!pos[x]){
    					if(!fir[x]){
    						if(b[x]==0)spred(x,1);
							fir[x]=1;
    					}else
    					if(cl[x]!=b[x]){
						    int val=(cl[x]==0)?-1:1;spred(x,val);
						}
    				}else{
    					if(b[x]==0){
    						for(int j=0;j<(int)tmp[pos[x]].size();++j){
    							int y=tmp[pos[x]][j];
    							if(tim[y])continue;
    							if(cl[y]==0&&is[y]==0){
									nex.push_back(y);
    							}
    						}
    						tmp[pos[x]].erase(tmp[pos[x]].begin(),tmp[pos[x]].end());
    					}
    				}
    				cl[x]=b[x];
    			}
    		}
    		for(int i=0;i<(int)ask.size();++i){
    			int x=ask[i];
    			if(!is[x]){
    				cl[x]=b[x];
    				if(cl[x]==0&&cnt[x]>0){
						nex.push_back(x);
    				}
    				for(int j=0;j<(int)fa[x].size();++j){
    					int y=fa[x][j];
    					if(is[x]==0&&is[y]&&cl[y]==0&&cl[x]==0){
							nex.push_back(x);
    					}
    				}
    				for(int j=0;j<(int)fa[x].size();++j){
    					int y=fa[x][j];
    					if(is[x]==0)tmp[pos[y]].push_back(x);
    				}
    			}
    		}
    		for(int i=0;i<(int)ask.size();++i){
    			tim[ask[i]]=0,b[ask[i]]=0;
    		}
    		ask.erase(ask.begin(),ask.end());
    		sort(nex.begin(),nex.end());
    		nex.erase(unique(nex.begin(),nex.end()),nex.end());
    		for(int i=0;i<(int)nex.size();++i){
    			int x=nex[i];
    			ask.push_back(x);is[x]=1;b[x]=0,tim[x]=1;
    		}
    		nex.erase(nex.begin(),nex.end());
    	}
    }
    return 0;
}

這時,我們開始思考為什麼(我這麼蠢)不是一張圖,而是樹,畢竟 根號演算法圖也可以跑。發現圖和樹的區別就是是否有確定的父子關係。
這時一旦有父子關係,我們直接開 v e c t o r vector vector 維護,如果一個點 x x x已經感染被解封,那麼把他父親丟進①集合,把它丟進②集合,再把它丟進父親的集合。每次開始感染就遍歷①集合,遍歷②集合中點的子集合即可。
時間複雜度 O ( n + q ) O(n+q) O(n+q)
@2328995024

#include<bits/stdc++.h>
#define ll long long
#define zhynb 0
using namespace std;
int n,m,q,gr[500005],fc[500005],hd[500005],ed[1000005],nxt[1000005],tot=1,bj[1000005],op[500005],xl[500005],tt,pd[500005],flg[500005];
struct Node
{
	int a,b;
} ;
vector <Node> s;
vector <int> ls,h[500005];
int read()
{
	int op=1,sum=0;
	char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') op=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+ch-'0',ch=getchar();
	return op*sum;
}
void add(int x,int y) {ed[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;}
void cb(int x)
{
	for(int i=hd[x];i;i=nxt[i])
	{
		int y=ed[i];
		if(!gr[y]) s.push_back((Node){x,y});
	}
}
int main()
{
	n=read();m=read();q=read();
	for(int i=1;i<n;++i)
	{
		int x=read(),y=read();
		add(x,y);add(y,x);
	}
	for(int i=1;i<=m;++i)
	{
		int x=read();
		gr[x]=1;
		cb(x);
	}
	for(int i=1;i<=q;++i)
	{
		op[i]=read();
		if(op[i]!=4) xl[i]=read();
	}
	++q;op[q]=4;
	int now=0;
	while(now<q)
	{
		int temp=0;
		for(int i=now+1;i<=q;++i)
		{
			if(op[i]==4) {temp=i;break;}
			if(op[i]!=3) continue;
			if(gr[xl[i]]) putchar('Y'),putchar('\n');
			else putchar('N'),putchar('\n');
		}
		++tt;
		for(int i=temp;i>now;--i)
		{
			if(op[i]<=2)
				if(pd[xl[i]]!=tt) pd[xl[i]]=tt,flg[i]=1;
		}
		for(int i=now+1;i<temp;++i)
		{
			if(!flg[i]) continue;
			if(op[i]==1) fc[xl[i]]=1;
		}
		for(int i=now+1;i<temp;++i)
		{
			if(!flg[i]) continue;
			if(op[i]==2)
			{
				fc[xl[i]]=0;
				for(int j=0;j<(int)h[xl[i]].size();++j)
				{
					if(fc[h[xl[i]][j]]) h[h[xl[i]][j]].push_back(xl[i]);
					else s.push_back((Node){xl[i],h[xl[i]][j]});
				}
				h[xl[i]].clear();
			}
		}
		for(int i=0;i<(int)s.size();++i)
		{
			int x=s[i].a,y=s[i].b;
			if(gr[x]+gr[y]==1&&fc[x]+fc[y]==0)
			{
				if(gr[x]) gr[y]=1,ls.push_back(y);
				else gr[x]=1,ls.push_back(x);
			}
			else if(gr[x]+gr[y]==1)
			{
				if(fc[y]) h[y].push_back(x);
				else h[x].push_back(y); 
			}
		}
		s.clear();
		for(int i=0;i<(int)ls.size();++i) cb(ls[i]);ls.clear();
		now=temp;
	}
	return zhynb;
} 

相關文章