BZOJ 1095: [ZJOI2007]Hide 捉迷藏
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 捉迷藏的更多相关文章
- 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV
意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)
这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治
[题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...
- [BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)
神做法-%dalao,写的超详细 konjac的博客. 如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码- CODE WITH ANNOTATION 代码中−6-6−6表示左括号'[',用−9 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆
写了7k多,可以说是一己之力切掉了这道毒瘤题~ 开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)
传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...
随机推荐
- VehicleCamera解读
坐标系: z-axis ^ | | y-axis | / | / |/ +----------------> x-axis 围绕Z轴旋转叫做偏航角,Yaw:围绕X轴旋转叫做 俯仰角,Pitch: ...
- Windows10下安装OpenSSL
Windows10下安装的方法 安装环境:Windows10专业版+VS2013 工具:ActivePerl-5.22.1.2201-MSWin32-x64-299574.msi,下载地址:http: ...
- JavaScript基础语法
首先,JavaScript的基本语法是以名为ECMAScript的伪语言定义的,理解ECMAScript的细节就是理解它在浏览器中实现的关键,目前大多数浏览器都遵循了ECMAScript第3版的,但是 ...
- oracle的round函数和trunc函数
--Oracle trunc()函数的用法/**************日期********************/1.select trunc(sysdate) from dual --2013- ...
- Azure 带宽
Azure带宽与Azure Blob云存储 http://www.cnblogs.com/threestone/p/4497625.html
- Android公共技术收集
UML类图详解 详解Android主流框架不可或缺的基石(ClassLoader,泛型,反射,注解) 公共技术点之 Java注解Annotation 公共技术点之 Java反射Reflection ...
- Android基础总结(三)
测试 黑盒测试 测试逻辑业务 白盒测试 测试逻辑方法 根据测试粒度 方法测试:function test 单元测试:unit test 集成测试:integration test 系统测试:syste ...
- Atomikos实现多数据源的事物管理
之前试过使用Spring动态切换数据库,通过继承AbstractRoutingDataSource重写determineCurrentLookupKey()方法,来决定使用那个数据库.在开启事务之前, ...
- NodeJS 爬虫爬取LOL英雄联盟的英雄信息,批量下载英雄壁纸
工欲善其事,必先利其器,会用各种模块非常重要. 1.模块使用 (1)superagent:Nodejs中的http请求库(每个语言都有无数个,java的okhttp,OC的afnetworking) ...
- codevs 2287 火车站
2287 火车站 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 钻石 Diamond 题目描述 Description 火车从始发站(称为第1站)开出,在始发站上车的人 ...