BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆
写了7k多,可以说是一己之力切掉了这道毒瘤题~
开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解.
由于需要支持堆的删除,所以写起来特别恶心+麻烦.
细节巨多~
#include <bits/stdc++.h> #include <cstdio> #include <queue> #include <algorithm> #define N 200004 #define setIO(s) freopen(s".in","r",stdin) // , freopen(s".out","w",stdout) using namespace std; int edges,n; int hd[N],to[N<<1],nex[N<<1]; void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } struct Queue { priority_queue<int>q; priority_queue<int>del; void re() { while(!q.empty()&&!del.empty()&&q.top()==del.top()) q.pop(),del.pop(); } void pop() { re(); if(!q.empty()) q.pop(); } void push(int x) { re(); q.push(x); } int empty() { re(); return q.empty(); } int size() { re(); return q.size()-del.size(); } int top() { re(); if(!q.empty()) return q.top(); else return -1; } void erase(int x) { re(); del.push(x); } }F[N],G[N],Total; namespace tree { int dep[N],size[N],son[N],top[N],fa[N]; void dfs1(int u,int ff) { fa[u]=ff,dep[u]=dep[ff]+1,size[u]=1; for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff) { dfs1(to[i],u),size[u]+=size[to[i]]; if(size[to[i]]>size[son[u]]) son[u]=to[i]; } } void dfs2(int u,int tp) { top[u]=tp; if(son[u]) dfs2(son[u],tp); for(int i=hd[u];i;i=nex[i]) if(to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i]); } int LCA(int x,int y) { while(top[x]!=top[y]) dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]; return dep[x]<dep[y]?x:y; } int Dis(int x,int y) { return dep[x]+dep[y]-(dep[LCA(x,y)]<<1); } }; int root,sn; int mx[N],vis[N],Fa[N],size[N],sta[N]; void dfs(int u,int ff) { size[u]=1; for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff&&!vis[to[i]]) dfs(to[i],u),size[u]+=size[to[i]]; } void getroot(int u,int ff) { size[u]=1,mx[u]=0; for(int i=hd[u];i;i=nex[i]) if(!vis[to[i]]&&to[i]!=ff) getroot(to[i],u),mx[u]=max(mx[u],size[to[i]]),size[u]+=size[to[i]]; mx[u]=max(mx[u],sn-size[u]); if(mx[u]<mx[root]) root=u; } void work(int u,int ff,int rt) { if(Fa[rt]) G[rt].push(tree::Dis(Fa[rt],u)); for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff&&!vis[to[i]]) work(to[i],u,rt); } void calc(int u) { work(u,0,u); F[u].push(0); if(Fa[u]&&G[u].size()) F[Fa[u]].push(G[u].top()); } void prepare(int u) { vis[u]=1; calc(u); for(int i=hd[u];i;i=nex[i]) if(!vis[to[i]]) dfs(to[i],u),sn=size[to[i]],root=0,getroot(to[i],u),Fa[root]=u,prepare(root); if(F[u].size()>=2) { int a=0,b=0; a=F[u].top(), F[u].pop(); b=F[u].top(), F[u].pop(); Total.push(a+b); F[u].push(a), F[u].push(b); } } // 开灯 (更小) void open(int u,int key) { int a=0,b=0,a1=0,b1=0; if(F[u].size()>=2) { a=F[u].top(),F[u].pop(); b=F[u].top(),F[u].pop(); F[u].push(a),F[u].push(b),F[u].erase(key); if(F[u].size()>=2) { a1=F[u].top(),F[u].pop(); b1=F[u].top(),F[u].pop(); F[u].push(a1),F[u].push(b1); if(a1+b1!=a+b) { Total.erase(a+b); Total.push(a1+b1); } } else Total.erase(a+b); } else F[u].erase(key); } void shut(int u,int key) { int a=0,b=0,a1=0,b1=0; if(F[u].size()>=1) { if(F[u].size()>=2) { a=F[u].top(),F[u].pop(); b=F[u].top(),F[u].pop(); F[u].push(a),F[u].push(b),F[u].push(key); a1=F[u].top(),F[u].pop(); b1=F[u].top(),F[u].pop(); F[u].push(a1),F[u].push(b1); if(a1+b1!=a+b) { Total.erase(a+b); Total.push(a1+b1); } } else { a=F[u].top(),F[u].push(key); Total.push(a+key); } } else F[u].push(key); } // 开灯(更小) void update1(int u) { open(u,0); for(int U=u;Fa[u];u=Fa[u]) { int dis=tree::Dis(U,Fa[u]); if(G[u].top()==dis) { G[u].erase(dis); open(Fa[u],dis); if(!G[u].empty()) { int a=G[u].top(); shut(Fa[u],a); } } else G[u].erase(dis); } } // 关灯(更大) void update2(int u) { shut(u,0); for(int U=u;Fa[u];u=Fa[u]) { int dis=tree::Dis(U,Fa[u]); if(G[u].top()>=dis) G[u].push(dis); else if(G[u].empty()) { G[u].push(dis); shut(Fa[u],dis); } else { shut(Fa[u],dis); open(Fa[u],G[u].top()); G[u].push(dis); } } } int main() { int i,j,Q; // setIO("input"); scanf("%d",&n); for(i=1;i<n;++i) { int a,b; scanf("%d%d",&a,&b),add(a,b),add(b,a); } tree::dfs1(1,0),tree::dfs2(1,1); mx[0]=sn=n,root=0,getroot(1,0),prepare(root); scanf("%d",&Q); for(i=1;i<=Q;++i) { char str[2]; scanf("%s",str); if(str[0]=='C') { int u; scanf("%d",&u); if(sta[u]==0) { update1(u); } else { update2(u); } sta[u]^=1; } if(str[0]=='G') { if(Total.empty()) printf("-1\n"); else printf("%d\n",Total.top()); } } }