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

来源:互联网 发布:qt tcp客户端编程 编辑:程序博客网 时间:2024/06/01 07:56

传送门
题意
给定一棵树,树上的点是黑点或白点,修改一个点的颜色或查询树上两个最远黑点的距离
原本以为动态点分治是个什么很高级的东西
原来不是像LCT一样恶心的东西啊,但也很恶心了
问了问别人才知道所谓“动态点分治”只是把点分治时得到的信息存下来,用数据结构维护一下就可以了
如果知道了什么是动态点分治,这个题目用它来做的思路还是好YY的
对于每次找到的重心x,它的子树集是{Vi},那么对于每一个Vi建一个堆,来维护其中的黑点及其深度,我们称x的子树Vi所代表的堆为Q1xi
特殊的,把x自身也建一个堆出来Q1xx
每一个Q1堆中的元素最多是n个,|Q1|大概是O(nlogn)
(我原本以为这样的堆最多大概有nlogn个,但在测试样例时发现是O(n)数量级的,仔细想了想发现的确如此,虽然对程序没有太大影响,但这很不应该)
然后再对于每一个x建一个堆Q2x={max{Q1xi}}
|Q2|大概是O(n)
再在全局搞一个堆Q3={max{Q2x}+secondlarge{Q2x}|x=1..n}
查询时取Q3max就可以了
修改时比较麻烦
在分治过程中每个点被遍历logn次,所以要修改lognQ1
具体过程可以描述为
要修改的点是i,i是子树集v里的点,现在要求改重心为x时的情况
先在Q3中删掉max{Q2x}+secondlarge{Q2x}
再在Q2v中删去max{Q1xv}
Q1xv添加/删除i的信息
再在Q2v中加入max{Q1xv}
最后在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 100005using 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 100005using 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);                }                           }        }    }}
0 0