bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习

好迷啊。。。感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn

(静态)点分治大概是递归的时候分类讨论:

  1.答案经过当前点,暴力(雾)算

  2.答案不经过当前点,继续递归

由于原树可以长的奇形怪状(菊花啊、、链啊、、扫把啊、、)这就导致各种方法都会被卡

于是通过每次找重心保证最大深度

动态怎么解决呢?

不妨考虑线段树是二分的固态版本(只可意会),那么我们把每次找到的重心固定下来长成一棵树就可以把点分治凝固(不可言传)

原来点分治该维护什么现在就维护什么。。。

(事实上我并没有写过静态点分治。。。好气啊╮(╯▽╰)╭)

我居然一度认为新建的树的节点要连到所在子树外一定要经过该子树的根。。。太思博了

实现细节:

  1.有一个带删堆,直接拉了板子(拉了才知道实现那么简单,本来以为手打)

  2.lca以前习惯rmq(复杂度优异就是自信),现在改成倍增了(可能是之前写了个长链剖分的缘故)

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int Mn=100005;
  4 int cnt=0,h[Mn],n,m,vst[Mn],maxx,tg,s[Mn],sz,prt[Mn];
  5 int d[Mn],p[Mn][21],co[Mn];
  6 struct Priority_Queue{
  7     priority_queue<int> q,del;
  8     void push(int x)
  9     {q.push(x);}
 10     void erase(int x){del.push(x);}
 11     int top()
 12     {
 13         while(del.size()&&del.top()==q.top())
 14             {del.pop();q.pop();}
 15         return q.top();
 16     }
 17     void Pop()
 18     {
 19         while(del.size()&&del.top()==q.top())
 20             del.pop(),q.pop();
 21         q.pop();
 22     }
 23     int sec_top()
 24     {
 25         int tmp=top();Pop();
 26         int se=top();push(tmp);
 27         return se;
 28     }
 29     int size()
 30     {
 31         return q.size()-del.size();
 32     }
 33 }c[Mn],f[Mn],ans;
 34 struct Edge{int to,next;}w[Mn*2];
 35 void add(int x,int y)
 36 {w[++cnt]=(Edge){y,h[x]};h[x]=cnt;}
 37 void build(int x,int fa)
 38 {
 39     p[x][0]=fa;d[x]=d[fa]+1;
 40     for(int i=1;p[x][i-1];i++)
 41         p[x][i]=p[p[x][i-1]][i-1];
 42     for(int i=h[x];i;i=w[i].next)
 43     if(w[i].to!=fa)
 44         build(w[i].to,x);
 45 }
 46 void Insert(Priority_Queue &s){
 47      if(s.size()>1)ans.push(s.top()+s.sec_top());
 48 }
 49 void Erase(Priority_Queue &s){
 50      if(s.size()>1)ans.erase(s.top()+s.sec_top());
 51 }
 52 void DP(int x,int fa)
 53 {
 54      int j,y;s[x]=1;
 55      for(j=h[x];j;j=w[j].next)
 56      {
 57         y=w[j].to;
 58         if(y==fa||vst[y])continue;
 59         DP(y,x);
 60         s[x]+=s[y];
 61      }
 62 }
 63 void Biggest(int x,int fa){
 64      int j,y,mx=0;
 65      for(j=h[x];j;j=w[j].next){
 66         y=w[j].to;
 67         if(y==fa||vst[y])continue;
 68         Biggest(y,x);
 69         mx=max(mx,s[y]);
 70      }
 71      if(maxx>max(mx,sz-s[x])){
 72         maxx=max(mx,sz-s[x]);
 73         tg=x;
 74      }
 75 }
 76 int gg(int x)//get G
 77 {
 78     maxx=n+1;tg=0;
 79     DP(x,0);
 80     sz=s[x];
 81     Biggest(x,0);
 82     return tg;
 83 }
 84 int LCA(int x,int y){
 85     int j;
 86     if(d[x]<d[y])swap(x,y);
 87     for(j=20;j>=0;j--)
 88       if(d[p[x][j]]>=d[y])x=p[x][j];
 89     if(x==y)return x;
 90     for(j=20;j>=0;j--)
 91       if(p[x][j]!=p[y][j])
 92        {x=p[x][j];y=p[y][j];}
 93     return p[x][0];
 94 }
 95 int Dis(int x,int y){return d[x]+d[y]-2*d[LCA(x,y)];}
 96 void work(int x,int fa,int Gra){
 97      int j,y;
 98      f[Gra].push(Dis(x,prt[Gra]));
 99      for(j=h[x];j;j=w[j].next){
100         y=w[j].to;
101         if(y==fa||vst[y])continue;
102         work(y,x,Gra);
103      }
104 }
105 int mzz(int x,int fa)
106 {
107     int j,y,G,Gy;
108     G=gg(x);prt[G]=fa;
109     work(G,0,G);
110     vst[G]=1;
111     c[G].push(0);
112     for(j=h[G];j;j=w[j].next)
113     {
114         y=w[j].to;
115         if(!vst[y]){
116             Gy=mzz(y,G);
117             c[G].push(f[Gy].top());
118         }
119     }
120     Insert(c[G]);
121     return G;
122 }
123 void Light(int x){
124      Erase(c[x]);
125      c[x].erase(0);
126      Insert(c[x]);
127      for(int y=x;prt[y];y=prt[y]){
128         Erase(c[prt[y]]);
129         if(f[y].size())c[prt[y]].erase(f[y].top());
130         f[y].erase(Dis(x,prt[y]));
131         if(f[y].size())c[prt[y]].push(f[y].top());
132         Insert(c[prt[y]]);
133      }
134 }
135 void LiOut(int x){
136      Erase(c[x]);
137      c[x].push(0);
138      Insert(c[x]);
139      for(int y=x;prt[y];y=prt[y]){
140         Erase(c[prt[y]]);
141         if(f[y].size())c[prt[y]].erase(f[y].top());
142         f[y].push(Dis(x,prt[y]));
143         if(f[y].size())c[prt[y]].push(f[y].top());
144         Insert(c[prt[y]]);
145      }
146 }
147 void solve(){
148      int i,x;char ch[5];
149      cnt=n;
150      scanf("%d",&m);
151      for(i=1;i<=m;i++){
152         scanf("%s",ch);
153         if(ch[0]==‘G‘){
154           if(cnt<=1)printf("%d\n",cnt-1);
155           else printf("%d\n",ans.top());
156         }
157         else{
158             scanf("%d",&x);
159             if(!co[x]){cnt--;Light(x);co[x]=1;}
160             else{cnt++;LiOut(x);co[x]=0;}
161         }
162      }
163 }
164 int main()
165 {
166     scanf("%d",&n);int x,y;
167     for(int i=1;i<n;i++)
168         scanf("%d%d",&x,&y),
169         add(x,y),add(y,x);
170     build(1,0);mzz(1,0);
171     solve();
172     return 0;
173 }  
时间: 2024-10-17 04:48:16

bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习的相关文章

【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达.游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的时候,所有的灯都没有被打开.每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激

BZOJ 1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆

题目大意:给定一棵树,一开始每个点都是黑点,多次改变某个点的状态或询问距离最远的两个黑点的距离 <珍爱生命远离STL可是我还是可耻地用了STL系列> 传说中的动态树分治...其实并没有那么神嘛= = ↑别听这傻瓜瞎说这货被STL卡了一天QAQ 我们把分治过程中遍历过的重心都连起来 上一层的重心链接下一层的重心 可以得到一棵新的树 下面我们开始讨论这棵新树 显然这棵树的高度不会超过O(logn) 然后我们每个节点开两个堆 第一个堆记录子树中所有节点到父亲节点的距离 第二个堆记录所有子节点的堆顶

bzoj 1095 [ZJOI2007]Hide 捉迷藏 动态点分治+堆

题面 题目传送门 解法 挺恶心的题 考虑动态点分治,先建出点分树 然后每一个点开两个堆,分别为\(a,b\) \(a_i\)表示点分树上\(i\)子树中所有节点在原树上和点分树中\(i\)父亲的距离,\(b_i\)表示点分树中\(i\)所有儿子的堆顶 再开一个堆\(ans\),存每一个\(b_i\)最大和次大值的和 在修改的时候,分两种情况考虑 但是本质都是一样的,就是在点分树上不断爬,爬到根为止,然后对当前点和父亲的\(a,b\)进行删除和加入 细节比较多,需要注意 重点:传入一个结构体参数的

[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治

[bzoj1095][ZJOI2007]Hide 捉迷藏 2015年4月20日7,8876 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达.游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的时候,所有的灯都没有被打开.每一次,孩子们只会躲藏在

【BZOJ1095】【ZJOI2007】捉迷藏 [动态点分治]

捉迷藏 Time Limit: 40 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏. 他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达. 游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯. 在起初

[BZOJ1095][ZJOI2007]Hide 捉迷藏

试题描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达.游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的时候,所有的灯都没有被打开.每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯.为了评估某一次

bzoj千题计划245:bzoj1095: [ZJOI2007]Hide 捉迷藏

http://www.lydsy.com/JudgeOnline/problem.php?id=1095 查询最远点对,带修改 显然可以用动态点分治 对于每个点,维护两个堆 堆q1[x] 维护 点分树x的子树中,所有黑点到x的点分树中父节点的距离 堆q2[x]维护 点分树x的子节点的堆q1的堆顶,即若y是x在点分树中的子节点,则q2[x].push(q1[y].top()) 再来维护一个全局的堆Q,维护所有q2的堆顶,即Q.push(q2[x].top()) #include<cmath> #

bzoj 1095 Hide 捉迷藏 - 动态点分治 -堆

捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达.游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯.在起初的时候,所有的灯都没有被打开.每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯.为了评估某一次游戏的复杂

bzoj千题计划252:bzoj1095: [ZJOI2007]Hide 捉迷藏

http://www.lydsy.com/JudgeOnline/problem.php?id=1095 点分树+堆 请去看 http://www.cnblogs.com/TheRoadToTheGold/p/8463436.html 线段树维护括号序列 对树进行dfs,入栈时加一个左括号,出栈时加一个右括号,那么书上两点间的距离=括号序列两点间不匹配括号数 例: 树1--2--3,2为根 括号序列为 (2(3)(1)) 2和1的距离 为 ()( = 1, 3和1的距离为 )( =2 具体怎么维