Description

一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离.

Sol

动态点分治.

动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的...

这样的树一共有 \(logn\) 层,每个节点维护一些信息.

s1[] 所有子节点到该节点的父重心,也就是上一个重心,所有距离的集合,需要满足插入删除询问最大值的操作,这里我直接用的multiset.

s2[] 所有子重心,就是下面一层的重心,到这个点的最大值分别是多少,需要满足插入删除询问最大值的操作,这里我直接用set.

S答案集合,过所有重心的最长链的集合,就是所有子重心到他的最大值+次大值,需要满足插入删除询问最大值的操作,这里我直接用set.

再加上一个 \(O(1)\) LCA来求一下距离.

这样第一次预处理的时候处理完所有事情,数据修改的时候呢...我的做法比较蠢但是好写,不用考虑那么多乱七八糟的东西..

直接求出整个链,因为一个点对下面的点是没有贡献的,直接向上找出来这一条由重心连成的链.

然后先删掉所有这个节点可能产生的贡献,修改,再重新统计这些节点的最大值..插入同理...

这样复杂度就变成了 \(O(nlog^2n)\) 数据结构有一个 \(log\) ,点分治有一个 \(log\) 修改也是 \(log^2\) 的

打着打着发现自己代码到了6K...其实很大一部分都是调试信息...

Code

/**************************************************************
Problem: 1095
User: BeiYu
Language: C++
Result: Accepted
Time:31445 ms
Memory:78796 kb
****************************************************************/ #include <bits/stdc++.h>
using namespace std; #define debug(a) cout<<#a<<"="<<a<<" "
#define mpr make_pair
typedef pair< int,int > pr;
const int N = 1e5+50;
const int M = 25; int n,m,k,rt,cw;
vector< pr > g[N];
int t[N],sz[N],ud[N],cl[N],frt[N]; set< pr,greater< pr > > S;
multiset< int,greater< int > > s1[N];
set< pr,greater< pr > > s2[N]; inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
inline char getc(char ch=getchar()) { while(ch>'Z' || ch<'A') ch=getchar();return ch; } void Print(set< pr,greater< pr > > &S) {
cout<<"--------start------------"<<endl;
for(set< pr >::iterator i=S.begin();i!=S.end();i++)
cout<<"("<<(*i).first<<" "<<(*i).second<<") ";
cout<<endl<<"----------over-----------"<<endl;
}
void Print(multiset< int,greater< int > > &S) {
cout<<"--------start------------"<<endl;
for(multiset< int >::iterator i=S.begin();i!=S.end();i++)
cout<<(*i)<<" ";
cout<<endl<<"----------over-----------"<<endl;
}
void SuperPrint() {
for(int i=1;i<=n;i++) cout<<frt[i]<<" ";cout<<endl; for(int i=1;i<=n;i++) cout<<i<<endl<<"--> s1[]"<<endl,Print(s1[i]),cout<<"--> s2[]"<<endl,Print(s2[i]); cout<<"--> S"<<endl;
Print(S);
}
void AddEdge(int fr,int to,int w) { g[fr].push_back(mpr(to,w)); } struct Tree {
int dp[N],ds[N],fw[N],ct;
int lg[N<<1],rq[N<<1][M],pow2[M]; void DFS(int u,int fa,int w) {
fw[u]=++ct,dp[u]=dp[fa]+1,rq[ct][0]=u,ds[u]=w;
for(int i=0,v;i<(int)g[u].size();i++)
if((v=g[u][i].first)!=fa) DFS(v,u,w+g[u][i].second),rq[++ct][0]=u;
}
void init() {
DFS(1,1,0);
pow2[0]=1;for(int i=1;i<M;i++) pow2[i]=pow2[i-1]<<1;
lg[0]=-1;for(int i=1;i<=ct;i++) lg[i]=lg[i>>1]+1;
for(int j=1;j<M;j++) for(int i=1;i<=ct;i++) if(i+pow2[j]-1<=ct){
int u=rq[i][j-1],v=rq[i+pow2[j-1]][j-1];
if(dp[u]<dp[v]) rq[i][j]=u;else rq[i][j]=v;
}
}
int Dis(int u,int v) {
if(fw[u]>fw[v]) swap(u,v);
int lg2=lg[fw[v]-fw[u]+1];
int lca=dp[rq[fw[u]][lg2]]<dp[rq[fw[v]-pow2[lg2]+1][lg2]] ? rq[fw[u]][lg2] : rq[fw[v]-pow2[lg2]+1][lg2];
return ds[u]+ds[v]-2*ds[lca];
}
}qt; int dis(int u,int v) { return qt.Dis(u,v); } void GetRoot(int u,int fa,int nn) {
sz[u]=1,t[u]=0;
for(int i=0,v;i<(int)g[u].size();i++)
if((v=g[u][i].first)!=fa && !ud[v])
GetRoot(v,u,nn),sz[u]+=sz[v],t[u]=max(t[u],sz[v]);
t[u]=max(t[u],nn-sz[u]);
if(t[u]<t[rt]) rt=u;
} void GetDis(int u,int fa,int ff,int spf) {
if(spf) s1[ff].insert(dis(u,spf));
for(int i=0,v;i<(int)g[u].size();i++)
if((v=g[u][i].first)!=fa && !ud[v]) GetDis(v,u,ff,spf);
} pr Getv(int x) {
if(s2[x].size()<2) return mpr(-1,-1);
else return mpr((*s2[x].begin()).first+(*(++s2[x].begin())).first,x);
} void GetAns(int u,int nn) {
ud[u]=1;
if(frt[u]) s1[u].insert(dis(u,frt[u]));s2[u].insert(mpr(0,u));
for(int i=0,v;i<(int)g[u].size();i++) if(!ud[v=g[u][i].first]) {
GetDis(v,u,u,frt[u]);
}
for(int i=0,v,ss;i<(int)g[u].size();i++) if(!ud[v=g[u][i].first]) {
rt=0,ss=sz[u]>sz[v]?sz[v]:nn-sz[u];
GetRoot(v,v,ss),frt[rt]=u,v=rt,GetAns(rt,ss);
s2[u].insert(mpr(*s1[v].begin(),v));
}
S.insert(Getv(u));
} //S All
//s1 son->father'sfather
//s2 sonmax
void Modify(int x) {
if(cl[x]) cw++;else cw--;
vector< int > tmp;
for(int i=x;i;i=frt[i]){ tmp.push_back(i); }
// for(int i=0;i<(int)tmp.size();i++) cout<<tmp[i]<<" ";cout<<endl;
if(cl[x]) {
for(int i=0;i<(int)tmp.size();i++) S.erase(Getv(tmp[i]));
for(int i=0;i<(int)tmp.size();i++) {
// if(!i) s2[tmp[i]].erase(mpr(0,tmp[i]));
// else
if(i && !s1[tmp[i-1]].empty()) s2[tmp[i]].erase(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
}
for(int i=0;i<(int)tmp.size();i++) s1[tmp[i]].insert(dis(x,frt[tmp[i]]));
for(int i=0;i<(int)tmp.size();i++) {
if(!i) s2[tmp[i]].insert(mpr(0,tmp[i]));
else s2[tmp[i]].insert(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
}
for(int i=0;i<(int)tmp.size();i++) S.insert(Getv(tmp[i])); }else {
for(int i=0;i<(int)tmp.size();i++) S.erase(Getv(tmp[i]));
// cout<<"--> S"<<endl;Print(S);
for(int i=0;i<(int)tmp.size();i++) {
if(!i) s2[tmp[i]].erase(mpr(0,tmp[i]));
else s2[tmp[i]].erase(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
}
// cout<<"--> s2[1]"<<endl;Print(s2[1]);
// cout<<"--> s2[3]"<<endl;Print(s2[3]); for(int i=0;i<(int)tmp.size();i++) if(frt[tmp[i]]) s1[tmp[i]].erase(s1[tmp[i]].find(dis(x,frt[tmp[i]])));
for(int i=0;i<(int)tmp.size();i++) {
// if(!i) s2[tmp[i]].insert(mpr(0,tmp[i]));
// else
if(i && !s1[tmp[i-1]].empty()) s2[tmp[i]].insert(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
}
// cout<<"--> s2[1]"<<endl;Print(s2[1]);
for(int i=0;i<(int)tmp.size();i++) S.insert(Getv(tmp[i]));
}cl[x]^=1;
} void init() {
cw=n=in();
for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=1,AddEdge(u,v,w),AddEdge(v,u,w);
// for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=in(),AddEdge(u,v,w),AddEdge(v,u,w);
qt.init();
t[0]=N;
GetRoot(1,1,n);
GetAns(rt,n);
} int main() {
// freopen("in.in","r",stdin);
init(); // SuperPrint(); // Print(S);
for(int q=in();q--;) {
// cout<<"QAQ"<<endl<<endl;
if(getc()=='C') {
int x=in();Modify(x);
// cout<<"--> S"<<endl;Print(S);
// cout<<"--> s1[3]"<<endl;Print(s1[3]);
// cout<<"--> s2[3]"<<endl;Print(s2[3]);
// SuperPrint();
}else {
if(!cw) puts("-1");
else if(cw==1) puts("0");
else printf("%d\n",(*S.begin()).first);
}
}
return 0;
}

  

BZOJ 1095: [ZJOI2007]Hide 捉迷藏的更多相关文章

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

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

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

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

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

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

  4. 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV

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

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

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

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

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

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

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

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

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

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

    传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...

随机推荐

  1. ElasticSearch第三步-中文分词

      ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticS ...

  2. 使用EXtjs6.2构建web项目

    一.项目简介 众所周知ext是一款非常强大的表格控件,尤其是里边的grid为用户提供了非常多的功能,现在主流的还是用extjs4.0-4.2,但是更高一点的版本更加符合人的审美要求.因此,在今天咱们构 ...

  3. Java简易日历的实现

    import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; imp ...

  4. 如何设置Oracle客户端与服务器的字符集一致

    查看 Oracle 服务器字符集 select userenv('language') from dual; 设置Oracle客户端字符集 添加环境变量NLS_LANG 值与服务器的Oracle服务器 ...

  5. How to Disable Strict SQL Mode in MySQL 5.7

    If your app was written for older versions of MySQL and is not compatible with strict SQL mode in My ...

  6. 关于List的ConcurrentModificationException

    对ArrayList的操作我们可以通过索引象来访问,也可以通过Iterator来访问,只要不对ArrayList结构上进行修改都不会造成ConcurrentModificationException, ...

  7. 一.Jenkins安装

    1.Java安装: 安装包:jdk-8u73-windows-x64.exe.jdk-8u73-windows-i586.exe(i586是32位系统包) Java环境变量配置:http://jing ...

  8. ApacheCommons的Java公共类库(实现如Log这些功能)

    Apache Commons是Apache软件基金会的项目,曾隶属于Jakarta项目.Commons的目的是提供可重用的.开源的Java代码. 解释:http://baike.baidu.com/i ...

  9. supervisor监管进程max file descriptor配置不生效的问题

    配置了 sudo vim /etc/security/limits.conf * soft nofile * hard nofile   单独起进程没问题, 放到supervisor下监管启动,则报错 ...

  10. sublime的插件安装

    如何将Emmet安装到到 Sublime text 3?   看清楚哦~~这是Sublime text 3不是2的版本,两者的安装还是有区别的,下面的方法是我感觉比较简单的,其他的要命令什么的感觉太复 ...