意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次。因此原树上任意一个节点都会出现在点分树上,且是恰好一次

https://www.cnblogs.com/zzqsblog/p/6393023.html

对比http://www.cnblogs.com/hehe54321/p/8570320.html的普通点分程序,"到分治树上这个点父亲的距离"相当于solve(u)时各个cal函数计算出的值对ans的总贡献,只不过改成了动态维护这个值。

普通点分由"分治树上这个点父亲"来计算"这个点"的贡献,需要容斥解决(当然这道题维护所求值不需要容斥);这道题则维护某个重心管辖的连通块中各个点到该重心的上层重心的距离,这样修改某个点的贡献时,就可以修改该点到最上层重心的各个点维护的关于该点的信息。

不能维护各个点到该重心的距离,一定要维护到上层重心的距离,否则无法区分开各个子树。

(失败代码:

#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
struct E
{
int to,nxt;
}e[];
int f1[],ne;
int ff[],n,sum,fx[],dep[],sz[];
int eu[],pos[],dpx[],st[][],log2x[];
int root;
bool fl[],vis[];
multiset<int> s[],s2;
//s[i]:i点管辖的连通块各个点到i点的距离
//s2:各个s的最大值
int getdis(int x,int y)
{
int l=pos[x],r=pos[y];if(l>r) swap(l,r);
int k=log2x[r-l+],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-(<<k)+][k]]]?st[r-(<<k)+][k]:st[l][k];
return dpx[pos[x]]+dpx[pos[y]]-*dpx[pos[t]];
}
void getroot(int u,int fa)
{
sz[u]=;fx[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getroot(e[k].to,u);
sz[u]+=sz[e[k].to];
fx[u]=max(fx[u],sz[e[k].to]);
}
fx[u]=max(fx[u],sum-sz[u]);
if(fx[u]<fx[root]) root=u;
}
void getsz(int u,int fa)
{
sz[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getsz(e[k].to,u);
sz[u]+=sz[e[k].to];
}
}
void getdeep(int u,int fa)
{
s[root].insert(dep[u]);
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
dep[e[k].to]=dep[u]+;
getdeep(e[k].to,u);
}
}
char tmp[];
int getmax2(int p)
{
if(s[p].size()<) return -0x3f3f3f3f;
auto it=s[p].rbegin();int ans=;
ans+=*it;++it;ans+=*it;
return ans;
}
void solve(int u)
{
vis[u]=;
dep[u]=;getdeep(u,);s2.insert(getmax2(u));
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to])
{
getsz(e[k].to,);sum=sz[e[k].to];
root=;getroot(e[k].to,);
ff[root]=u;
solve(root);
}
}
void dfs1(int u,int fa,int d)
{
eu[++eu[]]=u;pos[u]=eu[];dpx[eu[]]=d;
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
dfs1(e[k].to,u,d+);
eu[++eu[]]=u;
dpx[eu[]]=d;
}
} void debugxxxx(multiset<int>& s)
{
for(auto i : s) printf("%d ",i);
puts("test");
}
void change(int u)
{
int now;
for(now=u;now;now=ff[now])
{
s2.erase(s2.find(getmax2(now)));
if(!fl[u]) s[now].erase(s[now].find(getdis(u,now)));
}
fl[u]^=;
for(now=u;now;now=ff[now])
{
if(!fl[u]) s[now].insert(getdis(u,now));
s2.insert(getmax2(now));
}
}
int main()
{
fx[]=0x3f3f3f3f;
int i,j,a,b,la=,q,t;
for(i=;i<=;i++)
{
if(i>=(<<(la+))) ++la;
log2x[i]=la;
}
scanf("%d",&n);
for(i=;i<n;i++)
{
scanf("%d%d",&a,&b);
e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
}
dfs1(,,);
for(i=;i<=eu[];i++) st[i][]=eu[i];
for(j=;(<<j)<=eu[];j++)
for(i=;i+(<<j)-<=eu[];i++)
if(dpx[pos[st[i][j-]]]>dpx[pos[st[i+(<<(j-))][j-]]])
st[i][j]=st[i+(<<(j-))][j-];
else
st[i][j]=st[i][j-];
//getdis(5,4);
sum=n;getroot(,);
solve(root);
scanf("%d",&q);
while(q--)
{
scanf("%s",tmp);
if(tmp[]=='G')
{
printf("%d\n",*s2.rbegin());
}
else if(tmp[]=='C')
{
scanf("%d",&t);
change(t);
}
}
return ;
}

)

最终代码(洛谷A不掉,好像被卡常了?)

#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
struct E
{
int to,nxt;
}e[];
int f1[],ne;
int ff[],n,sum,fx[],sz[];
int eu[],pos[],dpx[],st[][],log2x[],lft[];
int root;
bool fl[],vis[];
multiset<int> s[],s2[],s3;
//s[i]:i点管辖的连通块各个点到i点上层重心的距离
//s2[i]:i点的各个下层重心的s的最大值,**再加上一个0(i点到自身距离)
//s3:各个s2的前2大值之和
int getdis(int x,int y)
{
int l=pos[x],r=pos[y];if(l>r) swap(l,r);
int k=log2x[r-l+],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+][k]]]?st[r-lft[k]+][k]:st[l][k];
return dpx[pos[x]]+dpx[pos[y]]-*dpx[pos[t]];
}
void getroot(int u,int fa)
{
sz[u]=;fx[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getroot(e[k].to,u);
sz[u]+=sz[e[k].to];
fx[u]=max(fx[u],sz[e[k].to]);
}
fx[u]=max(fx[u],sum-sz[u]);
if(fx[u]<fx[root]) root=u;
}
void getsz(int u,int fa)
{
sz[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getsz(e[k].to,u);
sz[u]+=sz[e[k].to];
}
}
void getdeep(int u,int fa)
{
s[root].insert(getdis(u,ff[root]));
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
getdeep(e[k].to,u);
}
char tmp[];
int getmax2(int p)
{
if(s2[p].size()<) return -0x3f3f3f3f;
multiset<int>::reverse_iterator it=s2[p].rbegin();int ans=;
ans+=*it;++it;ans+=*it;
return ans;
}
void solve(int u)
{
vis[u]=;
s2[u].insert();
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to])
{
getsz(e[k].to,);sum=sz[e[k].to];
root=;getroot(e[k].to,);
ff[root]=u;getdeep(root,);
if(!s[root].empty()) s2[u].insert(*s[root].rbegin());
solve(root);
}
s3.insert(getmax2(u));
}
void dfs1(int u,int fa,int d)
{
eu[++eu[]]=u;pos[u]=eu[];dpx[eu[]]=d;
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
dfs1(e[k].to,u,d+);
eu[++eu[]]=u;
dpx[eu[]]=d;
}
}
//void debugxxxx(multiset<int>& s)
//{
// for(auto i : s) printf("%d ",i);
// puts("test");
//}
void change(int u)
{
int now;
s3.erase(s3.find(getmax2(u)));
if(!fl[u]) s2[u].erase(s2[u].find());
for(now=u;ff[now];now=ff[now])
{
s3.erase(s3.find(getmax2(ff[now])));
if(!s[now].empty()) s2[ff[now]].erase(s2[ff[now]].find(*s[now].rbegin()));
if(!fl[u]) s[now].erase(s[now].find(getdis(u,ff[now])));
}
fl[u]^=;
if(!fl[u]) s2[u].insert();
s3.insert(getmax2(u));
for(now=u;ff[now];now=ff[now])
{
if(!fl[u]) s[now].insert(getdis(u,ff[now]));
if(!s[now].empty()) s2[ff[now]].insert(*s[now].rbegin());
s3.insert(getmax2(ff[now]));
}
}
int num;
int main()
{
lft[]=;
fx[]=0x3f3f3f3f;
int i,j,a,b,la=,q,t;
for(i=;i<=;i++) lft[i]=(lft[i-]<<);
for(i=;i<=;i++)
{
if(i>=lft[la+]) ++la;
log2x[i]=la;
}
scanf("%d",&n);
for(i=;i<n;i++)
{
scanf("%d%d",&a,&b);
e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
}
dfs1(,,);
for(i=;i<=eu[];i++) st[i][]=eu[i];
for(j=;(<<j)<=eu[];j++)
for(i=;i+lft[j]-<=eu[];i++)
if(dpx[pos[st[i][j-]]]>dpx[pos[st[i+lft[j-]][j-]]])
st[i][j]=st[i+lft[j-]][j-];
else
st[i][j]=st[i][j-];
sum=n;getroot(,);
solve(root);
scanf("%d",&q);
num=n;
while(q--)
{
scanf("%s",tmp);
if(tmp[]=='G')
{
if(num==) printf("-1\n");
else if(num==) printf("0\n");
else printf("%d\n",*s3.rbegin());
}
else if(tmp[]=='C')
{
scanf("%d",&t);
if(fl[t]) num++;else num--;
change(t);
}
}
return ;
}

Qtree4卡不过去...算了不卡了,反正对拍没对出错(本地n=100000,q=100000随机数据1.5秒)

 #pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
struct E
{
int to,nxt,d;
}e[];
int f1[],ne;
int ff[],n,sum,fx[],sz[];
int eu[],pos[],dpx[],dpx2[],st[][],log2x[],lft[];
int root;
bool fl[],vis[];
multiset<int> s[],s2[],s3;
//s[i]:i点管辖的连通块各个点到i点上层重心的距离
//s2[i]:i点的各个下层重心的s的最大值,**再加上一个0(i点到自身距离)
//s3:各个s2的前2大值之和
int getdis(int x,int y)
{
int l=pos[x],r=pos[y];if(l>r) swap(l,r);
int k=log2x[r-l+],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+][k]]]?st[r-lft[k]+][k]:st[l][k];
return dpx2[pos[x]]+dpx2[pos[y]]-*dpx2[pos[t]];
}
void getroot(int u,int fa)
{
sz[u]=;fx[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getroot(e[k].to,u);
sz[u]+=sz[e[k].to];
fx[u]=max(fx[u],sz[e[k].to]);
}
fx[u]=max(fx[u],sum-sz[u]);
if(fx[u]<fx[root]) root=u;
}
void getsz(int u,int fa)
{
sz[u]=;
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getsz(e[k].to,u);
sz[u]+=sz[e[k].to];
}
}
void getdeep(int u,int fa)
{
s[root].insert(getdis(u,ff[root]));
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
getdeep(e[k].to,u);
}
char tmp[];
int getmax2(int p)
{
if(s2[p].size()<) return -0x3f3f3f3f;
multiset<int>::reverse_iterator it=s2[p].rbegin();int ans=;
ans+=*it;++it;ans+=*it;
return ans;
}
void solve(int u)
{
vis[u]=;
s2[u].insert();
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to])
{
getsz(e[k].to,);sum=sz[e[k].to];
root=;getroot(e[k].to,);
ff[root]=u;getdeep(root,);
if(!s[root].empty()) s2[u].insert(*s[root].rbegin());
solve(root);
}
s3.insert(getmax2(u));
}
void dfs1(int u,int fa,int d,int d2)
{
eu[++eu[]]=u;pos[u]=eu[];dpx[eu[]]=d;dpx2[eu[]]=d2;
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
dfs1(e[k].to,u,d+,d2+e[k].d);
eu[++eu[]]=u;
dpx[eu[]]=d;
dpx2[eu[]]=d2;
}
}
//void debugxxxx(multiset<int>& s)
//{
// for(auto i : s) printf("%d ",i);
// puts("test");
//}
void change(int u)
{
int now;
s3.erase(s3.find(getmax2(u)));
if(!fl[u]) s2[u].erase(s2[u].find());
for(now=u;ff[now];now=ff[now])
{
s3.erase(s3.find(getmax2(ff[now])));
if(!s[now].empty()) s2[ff[now]].erase(s2[ff[now]].find(*s[now].rbegin()));
if(!fl[u]) s[now].erase(s[now].find(getdis(u,ff[now])));
}
fl[u]^=;
if(!fl[u]) s2[u].insert();
s3.insert(getmax2(u));
for(now=u;ff[now];now=ff[now])
{
if(!fl[u]) s[now].insert(getdis(u,ff[now]));
if(!s[now].empty()) s2[ff[now]].insert(*s[now].rbegin());
s3.insert(getmax2(ff[now]));
}
}
int num;
int main()
{
lft[]=;
fx[]=0x3f3f3f3f;
int i,j,a,b,la=,q,t,c;
for(i=;i<=;i++) lft[i]=(lft[i-]<<);
for(i=;i<=;i++)
{
if(i>=lft[la+]) ++la;
log2x[i]=la;
}
scanf("%d",&n);
for(i=;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);
e[++ne].to=b;e[ne].nxt=f1[a];e[ne].d=c;f1[a]=ne;
e[++ne].to=a;e[ne].nxt=f1[b];e[ne].d=c;f1[b]=ne;
}
dfs1(,,,);
for(i=;i<=eu[];i++) st[i][]=eu[i];
for(j=;(<<j)<=eu[];j++)
for(i=;i+lft[j]-<=eu[];i++)
if(dpx[pos[st[i][j-]]]>dpx[pos[st[i+lft[j-]][j-]]])
st[i][j]=st[i+lft[j-]][j-];
else
st[i][j]=st[i][j-];
sum=n;getroot(,);
solve(root);
scanf("%d",&q);
num=n;
while(q--)
{
scanf("%s",tmp);
if(tmp[]=='A')
{
if(num==) printf("They have disappeared.\n");
else if(num==) printf("0\n");
else printf("%d\n",max(*s3.rbegin(),));
}
else if(tmp[]=='C')
{
scanf("%d",&t);
if(fl[t]) num++;else num--;
change(t);
}
}
return ;
}

数据生成器

var random = Math.random, floor = Math.floor, exit = process.exit, print = console.log;
var n = 100000, q = 100000;
console.log(n);
var fa = new Array(n+1), a, b, ta, tb, idx;
for(i=1; i<=n; i++) fa[i] = i;
function find(x) {return x===fa[x]?x:fa[x]=find(fa[x]);}
for(i=1; i<n; i++) {
do {
a = floor(random()*n) + 1;
b = floor(random()*n) + 1;
ta = find(a);tb = find(b);
}
while(ta == tb);
fa[ta] = tb;
console.log(a+" "+b+" "+(floor(random()*21)-10));
}
console.log(q);
for(i=1; i<=q; i++) {
idx = floor(random()*2);
if (idx === 1) {
console.log("A");
}
else {
console.log("C "+(floor(random()*n)+1));
}
}

另有:捉迷藏特殊做法

洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV的更多相关文章

  1. 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)

    题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...

  2. BZOJ.1095.[ZJOI2007]捉迷藏(线段树 括号序列)

    BZOJ 洛谷 对树DFS得到括号序列.比如这样一个括号序列:[A[B[E][F[H][I]]][C][D[G]]]. 那比如\(D,E\)间的最短距离,就是将\(D,E\)间的括号序列取出:][[] ...

  3. BZOJ 1095: [ZJOI2007]Hide 捉迷藏

    Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...

  4. bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...

  5. 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  6. BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)

    这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...

  7. BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治

    [题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...

  8. [BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)

    神做法-%dalao,写的超详细 konjac的博客. 如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码- CODE WITH ANNOTATION 代码中−6-6−6表示左括号'[',用−9 ...

  9. BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆

    写了7k多,可以说是一己之力切掉了这道毒瘤题~ 开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ...

随机推荐

  1. 外排序 & 败者树 & 多路归并-学习

    来来来,根据这篇文章,学一下败者树吧: http://blog.csdn.net/whz_zb/article/details/7425152 一.胜者树 胜者树的一个优点是,如果一个选手的值改变了, ...

  2. 偏差-方差分解Bias-Variance Decomposition

    转自: http://www.cnblogs.com/jmp0xf/archive/2013/05/14/Bias-Variance_Decomposition.html

  3. [Angular] Modify User Provided UI with Angular Content Directives

    If we’re going to make our toggle accessible, we’ll need to apply certain aria attributes to the con ...

  4. Spark SQL 源代码分析之Physical Plan 到 RDD的详细实现

    /** Spark SQL源代码分析系列文章*/ 接上一篇文章Spark SQL Catalyst源代码分析之Physical Plan.本文将介绍Physical Plan的toRDD的详细实现细节 ...

  5. Navicat for MySQL无法连接到数据库怎么办

    注意端口就是3306,不要改成80之类的,访问数据库就是从这个端口过去的

  6. SQL 撤销索引、撤销表以及撤销数据库

    SQL 撤销索引.撤销表以及撤销数据库 通过使用 DROP 语句,可以轻松地删除索引.表和数据库. DROP INDEX 语句 DROP INDEX 语句用于删除表中的索引. 用于 MS Access ...

  7. 【SICP练习】149 练习4.5

    练习4-5 原文 Exercise 4.5. Scheme allows an additional syntax for cond clauses, ( => ). If evaluates ...

  8. 【知识梳理1】Android触摸事件机制

    前言 随着科学技术的发展,智能手机早已成为我们当代人身边不可缺少的"伙伴"之中的一个,堪比对象女友.每天我们对着手机反复的做着点击.滑动操作,而手机则随着我们的操作给我们展示她的精 ...

  9. codeforces 394E Lightbulb for Minister 简单几何

    题目链接:点我点我 题意:给定n个点. 以下n行给出这n个点坐标. 给定m个点,以下m行给出这m个点坐标. 这m个点是一个凸包,顺时针给出的. 问:在凸包上随意找一个点(x, y) 使得这个点距离n个 ...

  10. iOS 配置支付宝

    尽管非常easy,可是对于第一次接触支付宝配置的啊猿.有些细节摸不着头脑.今天就来写一个流程配置. 1.创建一个project,然后再创建一个目录,把支付宝sdk要用到的都拖到目录中.然后拖到proj ...