您的位置:首页 > 其它

【BZOJ1095】捉迷藏,动态点分治

2016-12-15 10:37 393 查看
传送门

题意

给定一棵树,树上的点是黑点或白点,修改一个点的颜色或查询树上两个最远黑点的距离

原本以为动态点分治是个什么很高级的东西

原来不是像LCT一样恶心的东西啊,但也很恶心了

问了问别人才知道所谓“动态点分治”只是把点分治时得到的信息存下来,用数据结构维护一下就可以了

如果知道了什么是动态点分治,这个题目用它来做的思路还是好YY的

对于每次找到的重心x,它的子树集是{Vi},那么对于每一个Vi建一个堆,来维护其中的黑点及其深度,我们称x的子树Vi所代表的堆为Q1x−i

特殊的,把x自身也建一个堆出来Q1x−x

每一个Q1堆中的元素最多是n个,∑|Q1|大概是O(nlogn)

(我原本以为这样的堆最多大概有nlogn个,但在测试样例时发现是O(n)数量级的,仔细想了想发现的确如此,虽然对程序没有太大影响,但这很不应该)

然后再对于每一个x建一个堆Q2x={max{Q1x−i}}

∑|Q2|大概是O(n)

再在全局搞一个堆Q3={max{Q2x}+secondlarge{Q2x}|x=1..n}

查询时取Q3的max就可以了

修改时比较麻烦

在分治过程中每个点被遍历logn次,所以要修改logn个Q1

具体过程可以描述为

要修改的点是i,i是子树集v里的点,现在要求改重心为x时的情况

先在Q3中删掉max{Q2x}+secondlarge{Q2x}

再在Q2v中删去max{Q1x−v}

往Q1x−v添加/删除i的信息

再在Q2v中加入max{Q1x−v}

最后在Q3中加入max{Q2x}+secondlarge{Q2x}

mrazer:“删除操作可以再开一个辅助堆,如果辅助堆的堆顶和真正堆的堆顶相等,就都弹出来,继续找下去”

UPD

对于Q1堆,Yveh大爷提供了一种更容易理解的想法

实际上可以把每次寻找到的重心合起来看做一棵树,就是父重心和子重心的关系

或者称之为重心重构树

对于每个重心的所有Q1堆,实际上存的是重构树中它所有子树到它本身的信息

复杂度O(mlog2n)

本来写起来就很麻烦了……

我又用了pair啥的……

然后在BZ上就MLE了,在cogs上就RE了

考虑到这样做会使辅助堆中加入很多元素但堆顶弹出来的会很少,导致M

所以一怒之下改成set

在BZ上跑了27s,在cogs上T了最后一个点(每个时限10s)

用尽浑身解数来卡常,算了一下要跑13~14s左右……

看了Po姐的博客发现其实不用pair,直接在堆中存距离就可以了

因为这些距离相等的点是可以看成等效的……

有时间再去想想神奇的括号序列做法和LCT做法

代码写得不可看

Code

set+pair

#include<cstdio>
#include<iostream>
#include<vector>
#include<set>
#include <cstdlib>
#define M 100005
using namespace std;
int n,m,G,tot,cnt;
int siz[M],mx[M],tmp[M],owner[M*15],first[M];
typedef pair<int,int>node;
vector<node>belong[M];
struct Node
{
int poi,fa,dis;
}q[M];
struct edge{
int v,next;
}e[M<<1];
set<node> Q1[M*15],Q2[M],Q3;
set<node>::iterator it;
bool vis[M],tp[M];
char *cp=(char *)malloc(20000000);
inline void in(int &x)
{
for (;*cp<'0'||*cp>'9';++cp);
for (x=0;*cp>='0'&&*cp<='9';++cp) x=x*10+(*cp)-48;
}
inline void out(int x)
{
if (!x) return;
out(x/10);
putchar(x%10+48);
}
inline void add(int x,int y)
{
e[++tot].v=y;e[tot].next=first[x];first[x]=tot;
e[++tot].v=x;e[tot].next=first[y];first[y]=tot;
}
void find(int x,int fa)
{
siz[x]=1;
mx[x]=0;
tmp[++tmp[0]]=x;
for (int i=first[x];i;i=e[i].next)
if (!vis[e[i].v]&&e[i].v!=fa)
find(e[i].v,x),
siz[x]+=siz[e[i].v],
mx[x]=max(mx[x],siz[e[i].v]);
}
void solve(int x)
{
tmp[0]=G=0;
find(x,0);
int i,z,now,head,tail,maxn;
for (i=1;i<=tmp[0];++i)
z=tmp[i],
mx[z]=max(tmp[0]-siz[z],mx[z]),
G=(!G||mx[G]>mx[z]?z:G);
vis[G]=1;
for (i=first[G];i;i=e[i].next)
if (!vis[e[i].v])
{
owner[++cnt]=G;
now=e[i].v,head=1,tail=1,maxn=1;
q[1]=(Node){e[i].v,0,1};
for (;head<=tail;++head)
{
x=q[head].poi;
belong[x].push_back(make_pair(q[head].dis,cnt));
Q1[cnt].insert(make_pair(q[head].dis,x));
for (int j=first[x];j;j=e[j].next)
if (e[j].v!=q[head].fa&&!vis[e[j].v])
q[++tail]=(Node){e[j].v,x,q[head].dis+1};
}
if (!Q1[cnt].empty())
it=Q1[cnt].end(),
--it,
Q2[G].insert(make_pair((*it).first,cnt));
}
owner[++cnt]=G;
belong[G].push_back(make_pair(0,cnt));
Q1[cnt].insert(make_pair(0,G));
it=Q1[cnt].end(),
--it;
Q2[G].insert(make_pair((*it).first,cnt));
node a,b;
if (!Q2[G].empty())
{
it=Q2[G].end();
--it;
a=*it;
if (it!=Q2[G].begin())
b=*(--it),
Q3.insert(make_pair(a.first+b.first,G));
}
x=G;
for (i=first[x];i;i=e[i].next)
if (!vis[e[i].v]) solve(e[i].v);
}
main()
{
fread(cp,1,20000000,stdin);
in(n);
int v,t,x,i,y;
for (i=1;i<n;++i)
in(x),in(y),
add(x,y);
tot=n;
solve(1);
node a,b;
for (in(m);m;--m)
{
++cp;
while (*cp!='G'&&*cp!='C') ++cp;
if (*cp=='G')
{
if (!tot) puts("-1");
if (tot==1) puts("0");
if (tot>1)
it=Q3.end(),
--it,
out((*it).first),
putchar('\n');
}
else
{
in(x);
tp[x]^=1;
tot+=(tp[x]?-1:1);
for (i=0;i<belong[x].size();++i)
{
v=belong[x][i].second;
t=owner[v];
if (!Q2[t].empty())
{
it=Q2[t].end();
--it;
a=*it;
if (it!=Q2[t].begin())
b=*(--it),
Q3.erase(make_pair(a.first+b.first,t));
}
if (!Q1[v].empty())
it=Q1[v].end(),
--it,
Q2[t].erase(make_pair((*it).first,v));
if (tp[x]) Q1[v].erase(make_pair(belong[x][i].first,x));
else Q1[v].insert(make_pair(belong[x][i].first,x));
if (!Q1[v].empty())
it=Q1[v].end(),
--it,
Q2[t].insert(make_pair((*it).first,v));
if (!Q2[t].empty())
{
it=Q2[t].end();
--it;
a=*it;
if (it!=Q2[t].begin())
b=*(--it),
Q3.insert(make_pair(a.first+b.first,t));
}
}
}
}
}


Code



#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include <cstdlib>
#define M 100005
using namespace std;
int n,G,tot,cnt;
int siz[M],mx[M],tmp[M],owner[M*2];
vector<int> e[M];
typedef pair<int,int>node;
vector<node>belong[M];
struct Node
{
int poi,fa,dis;
}q[M];
priority_queue<int> Q1[2][M*2],Q2[2][M*2],Q3[2];
//Q1存子树节点及距离 Q2存Q1编号及距离 Q3存各个重心及距离
bool vis[M],tp[M];
int in()
{
char ch=getchar();int t=0;
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') t=t*10+ch-48,ch=getchar();
return t;
}
void find(int x,int fa)
{
siz[x]=1;
mx[x]=0;
tmp[++tmp[0]]=x;
for (int v,i=0;i<e[x].size();++i)
{
v=e[x][i];
if (vis[v]||v==fa) continue;
find(v,x);
siz[x]+=siz[v];
mx[x]=max(mx[x],siz[v]);
}
}
void solve(int x)
{
tmp[0]=G=0;
find(x,0);
for (int i=1;i<=tmp[0];++i)
mx[tmp[i]]=max(tmp[0]-siz[tmp[i]],mx[tmp[i]]),
G=(!G||mx[G]>mx[tmp[i]]?tmp[i]:G);
vis[G]=1;
for (int v,i=0;i<e[G].size();++i)
{
v=e[G][i];
if (vis[v]) continue;
owner[++cnt]=G;
int now=v,head=1,tail=1,mx=1;
q[1]=(Node){v,0,1};
for (;head<=tail;++head)
{
v=q[head].poi;
belong[v].push_back(make_pair(q[head].dis,cnt));
Q1[0][cnt].push(q[head].dis);
for (int j=0;j<e[v].size();++j)
if (e[v][j]!=q[head].fa&&!vis[e[v][j]])
q[++tail]=(Node){e[v][j],v,q[head].dis+1};
}
if (!Q1[0][cnt].empty())
Q2[0][G].push(Q1[0][cnt].top());
}
owner[++cnt]=G;
belong[G].push_back(make_pair(0,cnt));
Q1[0][cnt].push(0);
Q2[0][G].push(Q1[0][cnt].top());
int a,b;
if (!Q2[0][G].empty())
{
a=Q2[0][G].top();
Q2[0][G].pop();
if (!Q2[0][G].empty())
b=Q2[0][G].top(),
Q3[0].push(a+b);
Q2[0][G].push(a);
}
x=G;
for (int v,i=0;i<e[x].size();++i)
{
v=e[x][i];
if (vis[v]) continue;
solve(v);
}
}
void Q1_clr(int v)
{
while (!Q1[0][v].empty()&&!Q1[1][v].empty()&&Q1[0][v].top()==Q1[1][v].top())
Q1[0][v].pop(),Q1[1][v].pop();
}
void Q2_clr(int v)
{
while (!Q2[0][v].empty()&&!Q2[1][v].empty()&&Q2[0][v].top()==Q2[1][v].top())
Q2[0][v].pop(),Q2[1][v].pop();
}

void Q3_clr()
{
while (!Q3[1].empty()&&!Q3[0].empty()&&Q3[1].top()==Q3[0].top())
Q3[0].pop(),Q3[1].pop();
}
main()
{
n=in();tot=n;
for (int x,y,i=1;i<n;++i)
x=in(),y=in(),
e[x].push_back(y),
e[y].push_back(x);
solve(1);
for (int m=in();m;--m)
{
char ch=getchar();
while (ch!='G'&&ch!='C') ch=getchar();
if (ch=='G')
{
if (!tot) puts("-1");
if (tot==1) puts("0");
if (tot>1)
Q3_clr(),
printf("%d\n",Q3[0].top());
}
else
{
int x=in();
tp[x]^=1;
if (tp[x]) --tot;
else ++tot;
for (int v,t,i=0;i<belong[x].size();++i)
{
v=belong[x][i].second;
t=owner[v];
Q2_clr(t);
if (!Q2[0][t].empty())
{
int a,b;
a=Q2[0][t].top();
Q2[0][t].pop();
Q2_clr(t);
if (!Q2[0][t].empty())
b=Q2[0][t].top(),
Q3[1].push(a+b),
Q3_clr();
Q2[0][t].push(a);
}
Q1_clr(v);
if (!Q1[0][v].empty())
{
Q2[1][t].push(Q1[0][v].top());
Q2_clr(t);
}
Q1[tp[x]][v].push(belong[x][i].first);
Q1_clr(v);
if (!Q1[0][v].empty())
{
Q2[0][t].push(Q1[0][v].top());
Q2_clr(t);
}
Q2_clr(t);
if (!Q2[0][t].empty())
{
int a,b;
a=Q2[0][t].top();
Q2[0][t].pop();
Q2_clr(t);
if (!Q2[0][t].empty())
b=Q2[0][t].top(),
Q3[0].push(a+b),
Q3_clr();
Q2[0][t].push(a);
}
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: