传送门
题意
给定一棵树,树上的点是黑点或白点,修改一个点的颜色或查询树上两个最远黑点的距离
原本以为动态点分治是个什么很高级的东西
原来不是像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
#include
#include
#include
#include
#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;
vectorbelong[M];
struct Node
{
int poi,fa,dis;
}q[M];
struct edge{
int v,next;
}e[M<<1];
set Q1[M*15],Q2[M],Q3;
set::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;ix),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;ix].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
#include
#include
#include
#include
#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;
vectorbelong[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;ix].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;iif (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;jif (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;ix].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;ix=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;ix].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);
}
}
}
}
}