洛谷 P2056 [ZJOI2007]捉迷藏 解題報告
P2056 [ZJOI2007]捉迷藏
題目描述
Jiajia和Wind是一對恩愛的夫妻,並且他們有很多孩子。某天,Jiajia、Wind和孩子們決定在家裡玩捉迷藏遊戲。他們的家很大且構造很奇特,由\(N\)個屋子和\(N-1\)條雙向走廊組成,這\(N-1\)條走廊的分佈使得任意兩個屋子都互相可達。
遊戲是這樣進行的,孩子們負責躲藏,Jiajia負責找,而Wind負責操縱這\(N\)個屋子的燈。在起初的時候,所有的燈都沒有被開啟。每一次,孩子們只會躲藏在沒有開燈的房間中,但是為了增加刺激性,孩子們會要求開啟某個房間的電燈或者關閉某個房間的電燈。為了評估某一次遊戲的複雜性,Jiajia希望知道可能的最遠的兩個孩子的距離(即最遠的兩個關燈房間的距離)。
我們將以如下形式定義每一種操作:
C(hange) i
改變第\(i\)個房間的照明狀態,若原來開啟,則關閉;若原來關閉,則開啟。G(ame)
開始一次遊戲,查詢最遠的兩個關燈房間的距離。
輸入輸出格式
輸入格式:
第一行包含一個整數\(N\),表示房間的個數,房間將被編號為\(1,2,3,\dots,N\)的整數。
接下來\(N-1\)行每行兩個整數\(a,b\),表示房間\(a\)與房間\(b\)之間有一條走廊相連。
接下來一行包含一個整數\(Q\),表示操作次數。接著\(Q\)行,每行一個操作,如上文所示。
輸出格式:
對於每一個操作\(Game\),輸出一個非負整數到hide.out,表示最遠的兩個關燈房間的距離。若只有一個房間是關著燈的,輸出\(0\)
說明
對於\(20\%\)的資料, \(N ≤50, M ≤100\);
對於\(60\%\)的資料, \(N ≤3000, M ≤10000\);
對於\(100\%\)的資料, \(N ≤100000, M ≤500000\)。
如果get到動態點分的思路了這題應該思路上就比較簡單了。
簡要的說一下,對每個點維護
分治子樹所有黑點到分治樹父親的距離
分治樹上每個兒子的子樹到自己的最大距離(就是上面一個的最大值的集合
然後外部開一個維護答案。
更新暴力跳節點更新就行了
我最開始用了\(\text{multiset}\)極限資料本地居然跑了\(30s\dots\)
然後改用\(\text{priority_queue}\)就過了(\(\text{queue}\)的思路不錯)
struct heap
{
std::priority_queue <int> ins,del;
void erase(){while(!del.empty()&&ins.top()==del.top())ins.pop(),del.pop();}
void push(int x){erase();ins.push(x);}
int top(){erase();return ins.top();}
int size(){return ins.size()-del.size();}
void pop(int x){del.push(x);erase();}
int sum()
{
erase();int ret=ins.top(),las=ret;
ins.pop();erase();ret+=ins.top(),ins.push(las);
return ret;
}
};
Code:
#include <cstdio>
#include <cctype>
#include <queue>
const int N=1e5+10;
int head[N],to[N<<1],Next[N<<1],edge[N<<1],cnt;
int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
return x*f;
}
struct heap
{
std::priority_queue <int> ins,del;
void erase(){while(!del.empty()&&ins.top()==del.top())ins.pop(),del.pop();}
void push(int x){erase();ins.push(x);}
int top(){erase();return ins.top();}
int size(){return ins.size()-del.size();}
void pop(int x){del.push(x);erase();}
int sum()
{
erase();int ret=ins.top(),las=ret;
ins.pop();erase();ret+=ins.top(),ins.push(las);
return ret;
}
}mxdis[N],mxson[N],ans;
void add(int u,int v,int w)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
namespace RMQDis
{
int dep[N],dis[N],st[N<<1][19],dfn[N],Log[N<<1],dfs_clock;
void dfs(int now,int fa)
{
dep[now]=dep[fa]+1;
st[dfn[now]=++dfs_clock][0]=now;
for(int v,i=head[now];i;i=Next[i])
if((v=to[i])!=fa)
dis[v]=dis[now]+edge[i],dfs(v,now),st[++dfs_clock][0]=now;
}
void init()
{
dfs(1,0);
for(int i=2;i<=dfs_clock;i++) Log[i]=Log[i>>1]+1;
for(int j=1;j<=18;j++)
{
for(int x,y,i=1;i<=dfs_clock-(1<<j)+1;i++)
{
x=st[i][j-1],y=st[i+(1<<j-1)][j-1];
st[i][j]=dep[x]<dep[y]?x:y;
}
}
}
int getdis(int x,int y)
{
int ret=dis[x]+dis[y];
x=dfn[x],y=dfn[y];
if(x>y) std::swap(x,y);
int d=Log[y+1-x],a=st[x][d],b=st[y-(1<<d)+1][d];
return ret-(dis[dep[a]<dep[b]?a:b]<<1);
}
}
int f[N],siz[N],del[N],si,rt,mi;
int n,m,col[N],oncnt;
void dfs1(int now,int fa)
{
siz[now]=1;int mx=0;
for(int v,i=head[now];i;i=Next[i])
if(!del[v=to[i]]&&v!=fa)
dfs1(v,now),siz[now]+=siz[v],mx=mx>siz[v]?mx:siz[v];
mx=mx>si-siz[now]?mx:si-siz[now];
if(mi>mx) mi=mx,rt=now;
}
void dfs2(int now,int w,int fa,int dep)
{
mxdis[w].push(dep);
for(int v,i=head[now];i;i=Next[i])
if(!del[v=to[i]]&&v!=fa)
dfs2(v,w,now,dep+1);
}
void updatains(int now)
{
if(mxson[now].size()>1)
ans.push(mxson[now].sum());
}
void updatadel(int now)
{
if(mxson[now].size()>1)
ans.pop(mxson[now].sum());
}
void divide(int now)
{
del[now]=1;
for(int v,i=head[now];i;i=Next[i])
{
if(!del[v=to[i]])
{
si=siz[v],mi=N;
dfs1(v,0),dfs2(v,rt,0,1),v=rt;
if(mxdis[v].size())
mxson[now].push(mxdis[v].top());
f[v]=now,divide(v);
}
}
mxson[now].push(0);
updatains(now);
}
void Ins(int now)
{
int las=now;
updatadel(now);
mxson[now].push(0);
updatains(now);
while(f[now])
{
updatadel(f[now]);
if(mxdis[now].size()) mxson[f[now]].pop(mxdis[now].top());
mxdis[now].push(RMQDis::getdis(f[now],las));
mxson[f[now]].push(mxdis[now].top());
updatains(now=f[now]);
}
}
void Del(int now)
{
int las=now;
updatadel(now);
mxson[now].pop(0);
updatains(now);
while(f[now])
{
updatadel(f[now]);
mxson[f[now]].pop(mxdis[now].top());
mxdis[now].pop(RMQDis::getdis(f[now],las));
if(mxdis[now].size()) mxson[f[now]].push(mxdis[now].top());
updatains(now=f[now]);
}
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("dew.out","w",stdout);
n=read();col[n]=1;
for(int u,v,w,i=1;i<n;i++)
{
u=read(),v=read(),w=read();
add(u,v,w),add(v,u,w);
col[i]=1;
}
RMQDis::init();
oncnt=si=n,mi=N,dfs1(1,0),divide(rt);
char op[4];m=read();
for(int u,i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='A')
{
if(oncnt==0) puts("They have disappeared.");
else if(oncnt==1) puts("0");
else printf("%d\n",ans.top());
}
else
{
u=read();
if(col[u]) --oncnt,Del(u);
else ++oncnt,Ins(u);
col[u]^=1;
}
}
return 0;
}
2018.12.5