DTOJ#5214. 第一题

传送门
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;
} 

猜你喜欢

转载自blog.csdn.net/CSDNzhanghongyu/article/details/110497616