DTOJ#5214. 第一題
傳送門
w
國非常的窮,因此在它們國家的
n
n
n 座城市之間,只有
n
−
1
n − 1
n−1 條道路使得它們連通。
而就在某一天,新型病毒在 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 n−1 行,每行兩個正整數 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 1≤n,q≤2000 |
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 1≤n,m,q≤100000 |
7 7 7 | 12 12 12 | 沒有特殊限制 |
對於所有資料,保證:
1 ≤ n , m , q ≤ 500000 1 \leq n, m, q \leq 500000 1≤n,m,q≤500000 。
1 ≤ x i , y i ≤ n 1 \leq x_i, y_i \leq n 1≤xi,yi≤n ,保證圖是連通的。
1 ≤ a i ≤ n 1 \leq a_i \leq n 1≤ai≤n ,保證 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 1≤opti≤4,1≤wwji≤n 。
首先,不得不感嘆我思路新奇。啥都能根號。
首先根號做法即對於修改,度數
<
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;
}
相關文章
- leetcode第一題LeetCode
- 考試試題A卷第一題
- 考試試題B卷第一題
- (1)刷題第一彈
- 過年的第一題
- 用 Rust 刷 leetcode 第一題RustLeetCode
- #題解 第一篇
- 第一章習題
- 2024.4 第一週做題記錄
- [每日一題] 第一題:判定是否互為字元重排每日一題字元
- 2020 KCTF秋季賽 | 第一題點評及解題思路
- 自學linux第一關練習題Linux
- 第一次面試的題面試
- 2018前端圈面試題第一彈前端面試題
- Js逆向之猿人學比賽第一題JS
- 【leetcode 簡單】 第一百零六題 壓縮字串LeetCode字串
- 第一章 聯言命題選言命題及其推理-練習題:6~12題
- 第一章 聯言命題選言命題及其推理-練習題:1~5題
- 第一章 聯言命題選言命題及其推理-練習題:13~18題
- 【第一彈】嵌入式工程師面試題工程師面試題
- LeetCode 演算法題系列(第一週 25道)LeetCode演算法
- VUE下拉框第一行空白問題Vue
- Leetcode第一題:兩數之和(3種語言)LeetCode
- Java 208 道面試題:第一模組答案Java面試題
- “有意思的前端函式面試題”第一題答案原理解析前端函式面試題
- 第一章 聯言命題選言命題及其推理-聯言命題性質
- 第一章 聯言命題選言命題及其推理-選言命題性質
- 2024ICPC網路賽第一場題解(部分)
- 肖sir__ 第一個月綜合面試題面試題
- leetcode第一百一十九題:楊輝三角ⅡLeetCode
- Codeforces673回合區域二第一題
- 西電--工程優化第一章習題優化
- LeetCode 之 JavaScript 解答第一題 —— 兩數之和(Two Sum)LeetCodeJavaScript
- 看雪.紐盾 KCTF 2019 Q3 | 第一題點評及解題思路
- 看雪.紐盾 KCTF 2019 Q2 | 第一題點評及解題思路
- 看雪CTF.TSRC 2018 團隊賽 第一題 『初世紀』 解題思路
- 第一章 聯言命題選言命題及其推理-德摩根定律及其練習題
- P11276 第一首歌 題解