bzoj1095 [ZJOI2007]Hide 捉迷藏(动态点分治+堆)
2018-01-08 21:53
633 查看
bzoj1095 [ZJOI2007]Hide 捉迷藏
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1095题意:
给出一个n个节点的树,最初所有的节点都是黑的。
有m个操作,操作有两种:
C x:x节点反色
G:查询树上最远的两个黑色点对之间的距离
数据范围
N ≤100000, M ≤500000。
题解:
静态和对拍都查了良久的错,最后终于对拍出来:
3
1 2
2 3
6
C 1
G
C 1
G
C 3
G
唉。
第一道动态点分治。
发现了几个错:
最开始建点分树时堆推错了,找中心也有问题。
后面判断堆是否为空时,写的是B堆,实际是A堆。
不仅要勤于注释,自己的色每个语句都要理清楚才是。
这个维护del堆来删除的操作积累。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=100010; const int M=1000005; const int P=20; int n,m,tot=0,head ,to[M],nxt[M],num=0,col ,fa ,size ,ss ,sz=0,root=0,dep ,anc [P+3],cnt; bool Del ; struct PQ { priority_queue<int> q,del; void insert(int x) {q.push(x);} void pop(){ while(!del.empty()&&q.top()==del.top()){q.pop(); del.pop();} q.pop();} int top() { while(!del.empty()&&q.top()==del.top()){q.pop(); del.pop();} return q.top(); } int sectop() { int u=top(); pop(); int ret=top(); insert(u); return ret; } void erase(int x){del.push(x);} int size() { return q.size()-del.size();} }A ,B ,C; /* * heap A--distance from sons to father * heap B--contributions of each sons tops from A * heap C--answers altogether tops and sectops from B */ void dfs(int u,int f) { anc[u][0]=f; for(int i=1;i<P;i++) anc[u][i]=anc[anc[u][i-1]][i-1]; dep[u]=dep[f]+1; for(int i=head[u];i;i=nxt[i]) { int v=to[i]; if(v==f) continue; dfs(v,u); } } int lca(int u,int v) { if(dep[u]<dep[v]) swap(u,v); int d=dep[u]-dep[v]; for(int i=0;d;d>>=1,i++) if(d&1) u=anc[u][i]; if(u==v) return u; for(int i=P-1;i>=0;i--) if(anc[u][i]!=anc[v][i]) {u=anc[u][i]; v=anc[v][i];} return anc[u][0]; } void build(int u,int v) { num++; to[num]=v; nxt[num]=head[u]; head[u]=num; } void getroot(int u,int f) { size[u]=1; ss[u]=0; for(int i=head[u];i;i=nxt[i]) { int v=to[i]; if(v==f||Del[v]) continue; getroot(v,u); size[u]+=size[v]; ss[u]=max(ss[u],size[v]); } ss[u]=max(ss[u],sz-size[u]); if(ss[root]>ss[u]) root=u; } int dis(int u,int v) { return dep[u]+dep[v]-2*dep[lca(u,v)]; } void getdis(int u,int f,int rt) { A[rt].insert(dis(u,fa[rt])); for(int i=head[u];i;i=nxt[i]) { int v=to[i]; if(v==f||Del[v]) continue; getdis(v,u,rt); } } void dp(int u,int f) { size[u]=1; for(int i=head[u];i;i=nxt[i]) { int v=to[i]; if(v==f||Del[v]) continue; dp(v,u); size[u]+=size[v]; } } int Build(int x,int f) { getroot(x,f);int u=root; fa[u]=f; getdis(u,f,u); B[u].insert(0); Del[u]=1; for(int i=head[u];i;i=nxt[i]) { int v=to[i]; if(Del[v]) continue; dp(v,u); sz=size[v]; root=0; int srt=Build(v,u); B[u].insert(A[srt].top()); } if(B[u].size()>1) C.insert(B[u].top()+B[u].sectop()); return u; } void modify(int u,int opt) { if(!opt) //light { if(B[u].size()>1) C.erase(B[u].top()+B[u].sectop()); B[u].erase(0); if(B[u].size()>1) C.insert(B[u].top()+B[u].sectop()); for(int x=u;fa[x];x=fa[x]) { int y=fa[x]; if(B[y].size()>1) C.erase(B[y].top()+B[y].sectop()); if(A[x].size()) B[y].erase(A[x].top()); A[x].erase(dis(u,y)); if(A[x].size()) B[y].insert(A[x].top()); if(B[y].size()>1) C.insert(B[y].top()+B[y].sectop()); } } else // light out { if(B[u].size()>1) C.erase(B[u].top()+B[u].sectop()); B[u].insert(0); if(B[u].size()>1) C.insert(B[u].top()+B[u].sectop()); for(int x=u;fa[x];x=fa[x]) { int y=fa[x]; if(B[y].size()>1) C.erase(B[y].top()+B[y].sectop()); if(A[x].size()) B[y].erase(A[x].top()); A[x].insert(dis(u,y)); if(A[x].size()) B[y].insert(A[x].top()); if(B[y].size()>1) C.insert(B[y].top()+B[y].sectop()); } } } int main() { scanf("%d",&n); for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); build(a,b); build(b,a); } dfs(1,1); cnt=n; for(int i=1;i<=n;i++) col[i]=1; root=0; ss[0]=n+1; sz=n; int whatever=Build(1,0); scanf("%d",&m); while(m--) { char opt[5]; scanf("%s",opt); if(opt[0]=='G') { if(cnt<=0) printf("-1\n"); else if(cnt==1) printf("%d\n",0); else printf("%d\n",C.top()); } else { int x; scanf("%d",&x); if(col[x]) {cnt--; modify(x,0);col[x]^=1;} else{cnt++; modify(x,1); col[x]^=1;} } } return 0; }
相关文章推荐
- [动态点分治] BZOJ1095: [ZJOI2007]Hide 捉迷藏
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治
- bzoj1095: [ZJOI2007]Hide 捉迷藏(动态点分治+树上ST表)
- bzoj 1095: [ZJOI2007]Hide 捉迷藏 (动态点分治)
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 【动态点分治 + 堆】
- 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏
- [bzoj1095][ZJOI2007]Hide 捉迷藏(动态点分治)
- 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏
- bzoj1095 [ZJOI2007]Hide 捉迷藏(动态点分治|括号序列)
- bzoj1095 [ZJOI2007]Hide 捉迷藏 括号序列/动态点分治/树的数据生成
- BZOJ_1095_[ZJOI2007]Hide 捉迷藏_动态点分治+堆
- BZOJ 1095 ZJOI 2007 Hide 捉迷藏 动态点分治
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏【动态树分治】
- 【BZOJ1095】【ZJOI2007】捉迷藏 [动态点分治]
- bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏
- bzoj1095 [ZJOI2007]Hide 捉迷藏
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
- BZOJ 1095 Hide 捉迷藏 详解(动态点分治 堆维护)
- [bzoj1095] [ZJOI2007]Hide 捉迷藏