洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4

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

https://www.cnblogs.com/zzqsblog/p/6393023.html

对比http://www.cnblogs.com/hehe54321/p/8570320.html的普通点分程序,"到分治树上这个点父亲的距离"相当于solve(u)时各个cal函数计算出的值对ans的总贡献,只不过改成了动态维护这个值。

普通点分由"分治树上这个点父亲"来计算"这个点"的贡献,需要容斥解决(当然这道题维护所求值不需要容斥);这道题则维护某个重心管辖的连通块中各个点到该重心的上层重心的距离,这样修改某个点的贡献时,就可以修改该点到最上层重心的各个点维护的关于该点的信息。

不能维护各个点到该重心的距离,一定要维护到上层重心的距离,否则无法区分开各个子树。

(失败代码:

#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
struct E
{
    int to,nxt;
}e[200100];
int f1[100100],ne;
int ff[100100],n,sum,fx[100100],dep[100100],sz[100100];
int eu[200100],pos[100100],dpx[200100],st[200100][20],log2x[200100];
int root;
bool fl[100100],vis[100100];
multiset<int> s[100100],s2;
//s[i]:i点管辖的连通块各个点到i点的距离
//s2:各个s的最大值
int getdis(int x,int y)
{
    int l=pos[x],r=pos[y];if(l>r)    swap(l,r);
    int k=log2x[r-l+1],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-(1<<k)+1][k]]]?st[r-(1<<k)+1][k]:st[l][k];
    return dpx[pos[x]]+dpx[pos[y]]-2*dpx[pos[t]];
}
void getroot(int u,int fa)
{
    sz[u]=1;fx[u]=0;
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to]&&e[k].to!=fa)
        {
            getroot(e[k].to,u);
            sz[u]+=sz[e[k].to];
            fx[u]=max(fx[u],sz[e[k].to]);
        }
    fx[u]=max(fx[u],sum-sz[u]);
    if(fx[u]<fx[root])    root=u;
}
void getsz(int u,int fa)
{
    sz[u]=1;
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to]&&e[k].to!=fa)
        {
            getsz(e[k].to,u);
            sz[u]+=sz[e[k].to];
        }
}
void getdeep(int u,int fa)
{
    s[root].insert(dep[u]);
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to]&&e[k].to!=fa)
        {
            dep[e[k].to]=dep[u]+1;
            getdeep(e[k].to,u);
        }
}
char tmp[20];
int getmax2(int p)
{
    if(s[p].size()<2)    return -0x3f3f3f3f;
    auto it=s[p].rbegin();int ans=0;
    ans+=*it;++it;ans+=*it;
    return ans;
}
void solve(int u)
{
    vis[u]=1;
    dep[u]=0;getdeep(u,0);s2.insert(getmax2(u));
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to])
        {
            getsz(e[k].to,0);sum=sz[e[k].to];
            root=0;getroot(e[k].to,0);
            ff[root]=u;
            solve(root);
        }
}
void dfs1(int u,int fa,int d)
{
    eu[++eu[0]]=u;pos[u]=eu[0];dpx[eu[0]]=d;
    for(int k=f1[u];k;k=e[k].nxt)
        if(e[k].to!=fa)
        {
            dfs1(e[k].to,u,d+1);
            eu[++eu[0]]=u;
            dpx[eu[0]]=d;
        }
}

void debugxxxx(multiset<int>& s)
{
    for(auto i : s)    printf("%d ",i);
    puts("test");
}
void change(int u)
{
    int now;
    for(now=u;now;now=ff[now])
    {
        s2.erase(s2.find(getmax2(now)));
        if(!fl[u])    s[now].erase(s[now].find(getdis(u,now)));
    }
    fl[u]^=1;
    for(now=u;now;now=ff[now])
    {
        if(!fl[u])    s[now].insert(getdis(u,now));
        s2.insert(getmax2(now));
    }
}
int main()
{
    fx[0]=0x3f3f3f3f;
    int i,j,a,b,la=0,q,t;
    for(i=1;i<=200000;i++)
    {
        if(i>=(1<<(la+1)))    ++la;
        log2x[i]=la;
    }
    scanf("%d",&n);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
        e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
    }
    dfs1(1,0,0);
    for(i=1;i<=eu[0];i++)    st[i][0]=eu[i];
    for(j=1;(1<<j)<=eu[0];j++)
        for(i=1;i+(1<<j)-1<=eu[0];i++)
            if(dpx[pos[st[i][j-1]]]>dpx[pos[st[i+(1<<(j-1))][j-1]]])
                st[i][j]=st[i+(1<<(j-1))][j-1];
            else
                st[i][j]=st[i][j-1];
    //getdis(5,4);
    sum=n;getroot(1,0);
    solve(root);
    scanf("%d",&q);
    while(q--)
    {
        scanf("%s",tmp);
        if(tmp[0]=='G')
        {
            printf("%d
",*s2.rbegin());
        }
        else if(tmp[0]=='C')
        {
            scanf("%d",&t);
            change(t);
        }
    }
    return 0;
}
View Code

)

最终代码(洛谷A不掉,好像被卡常了?)

#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
struct E
{
    int to,nxt;
}e[200100];
int f1[100100],ne;
int ff[100100],n,sum,fx[100100],sz[100100];
int eu[200100],pos[200100],dpx[200100],st[200100][20],log2x[200100],lft[30];
int root;
bool fl[100100],vis[100100];
multiset<int> s[100100],s2[100100],s3;
//s[i]:i点管辖的连通块各个点到i点上层重心的距离
//s2[i]:i点的各个下层重心的s的最大值,**再加上一个0(i点到自身距离)
//s3:各个s2的前2大值之和
int getdis(int x,int y)
{
    int l=pos[x],r=pos[y];if(l>r)    swap(l,r);
    int k=log2x[r-l+1],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+1][k]]]?st[r-lft[k]+1][k]:st[l][k];
    return dpx[pos[x]]+dpx[pos[y]]-2*dpx[pos[t]];
}
void getroot(int u,int fa)
{
    sz[u]=1;fx[u]=0;
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to]&&e[k].to!=fa)
        {
            getroot(e[k].to,u);
            sz[u]+=sz[e[k].to];
            fx[u]=max(fx[u],sz[e[k].to]);
        }
    fx[u]=max(fx[u],sum-sz[u]);
    if(fx[u]<fx[root])    root=u;
}
void getsz(int u,int fa)
{
    sz[u]=1;
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to]&&e[k].to!=fa)
        {
            getsz(e[k].to,u);
            sz[u]+=sz[e[k].to];
        }
}
void getdeep(int u,int fa)
{
    s[root].insert(getdis(u,ff[root]));
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to]&&e[k].to!=fa)
            getdeep(e[k].to,u);
}
char tmp[20];
int getmax2(int p)
{
    if(s2[p].size()<2)    return -0x3f3f3f3f;
    multiset<int>::reverse_iterator it=s2[p].rbegin();int ans=0;
    ans+=*it;++it;ans+=*it;
    return ans;
}
void solve(int u)
{
    vis[u]=1;
    s2[u].insert(0);
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to])
        {
            getsz(e[k].to,0);sum=sz[e[k].to];
            root=0;getroot(e[k].to,0);
            ff[root]=u;getdeep(root,0);
            if(!s[root].empty())    s2[u].insert(*s[root].rbegin());
            solve(root);
        }
    s3.insert(getmax2(u));
}
void dfs1(int u,int fa,int d)
{
    eu[++eu[0]]=u;pos[u]=eu[0];dpx[eu[0]]=d;
    for(int k=f1[u];k;k=e[k].nxt)
        if(e[k].to!=fa)
        {
            dfs1(e[k].to,u,d+1);
            eu[++eu[0]]=u;
            dpx[eu[0]]=d;
        }
}
//void debugxxxx(multiset<int>& s)
//{
//    for(auto i : s)    printf("%d ",i);
//    puts("test");
//}
void change(int u)
{
    int now;
    s3.erase(s3.find(getmax2(u)));
    if(!fl[u])    s2[u].erase(s2[u].find(0));
    for(now=u;ff[now];now=ff[now])
    {
        s3.erase(s3.find(getmax2(ff[now])));
        if(!s[now].empty())    s2[ff[now]].erase(s2[ff[now]].find(*s[now].rbegin()));
        if(!fl[u])    s[now].erase(s[now].find(getdis(u,ff[now])));
    }
    fl[u]^=1;
    if(!fl[u])    s2[u].insert(0);
    s3.insert(getmax2(u));
    for(now=u;ff[now];now=ff[now])
    {
        if(!fl[u])    s[now].insert(getdis(u,ff[now]));
        if(!s[now].empty())    s2[ff[now]].insert(*s[now].rbegin());
        s3.insert(getmax2(ff[now]));
    }
}
int num;
int main()
{
    lft[0]=1;
    fx[0]=0x3f3f3f3f;
    int i,j,a,b,la=0,q,t;
    for(i=1;i<=27;i++)    lft[i]=(lft[i-1]<<1);
    for(i=1;i<=200000;i++)
    {
        if(i>=lft[la+1])    ++la;
        log2x[i]=la;
    }
    scanf("%d",&n);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
        e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
    }
    dfs1(1,0,0);
    for(i=1;i<=eu[0];i++)    st[i][0]=eu[i];
    for(j=1;(1<<j)<=eu[0];j++)
        for(i=1;i+lft[j]-1<=eu[0];i++)
            if(dpx[pos[st[i][j-1]]]>dpx[pos[st[i+lft[j-1]][j-1]]])
                st[i][j]=st[i+lft[j-1]][j-1];
            else
                st[i][j]=st[i][j-1];
    sum=n;getroot(1,0);
    solve(root);
    scanf("%d",&q);
    num=n;
    while(q--)
    {
        scanf("%s",tmp);
        if(tmp[0]=='G')
        {
            if(num==0)    printf("-1
");
            else if(num==1)    printf("0
");
            else    printf("%d
",*s3.rbegin());
        }
        else if(tmp[0]=='C')
        {
            scanf("%d",&t);
            if(fl[t])    num++;else    num--;
            change(t);
        }
    }
    return 0;
}
View Code

Qtree4卡不过去...算了不卡了,反正对拍没对出错(本地n=100000,q=100000随机数据1.5秒)

  1 #pragma GCC optimize("Ofast")
  2 #pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
  3 #pragma GCC diagnostic error "-fwhole-program"
  4 #pragma GCC diagnostic error "-fcse-skip-blocks"
  5 #pragma GCC diagnostic error "-funsafe-loop-optimizations"
  6 #pragma GCC diagnostic error "-std=c++14"
  7 #include<cstdio>
  8 #include<algorithm>
  9 #include<set>
 10 using namespace std;
 11 struct E
 12 {
 13     int to,nxt,d;
 14 }e[200100];
 15 int f1[100100],ne;
 16 int ff[100100],n,sum,fx[100100],sz[100100];
 17 int eu[200100],pos[200100],dpx[200100],dpx2[200100],st[200100][20],log2x[200100],lft[30];
 18 int root;
 19 bool fl[100100],vis[100100];
 20 multiset<int> s[100100],s2[100100],s3;
 21 //s[i]:i点管辖的连通块各个点到i点上层重心的距离
 22 //s2[i]:i点的各个下层重心的s的最大值,**再加上一个0(i点到自身距离)
 23 //s3:各个s2的前2大值之和
 24 int getdis(int x,int y)
 25 {
 26     int l=pos[x],r=pos[y];if(l>r)    swap(l,r);
 27     int k=log2x[r-l+1],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+1][k]]]?st[r-lft[k]+1][k]:st[l][k];
 28     return dpx2[pos[x]]+dpx2[pos[y]]-2*dpx2[pos[t]];
 29 }
 30 void getroot(int u,int fa)
 31 {
 32     sz[u]=1;fx[u]=0;
 33     for(int k=f1[u];k;k=e[k].nxt)
 34         if(!vis[e[k].to]&&e[k].to!=fa)
 35         {
 36             getroot(e[k].to,u);
 37             sz[u]+=sz[e[k].to];
 38             fx[u]=max(fx[u],sz[e[k].to]);
 39         }
 40     fx[u]=max(fx[u],sum-sz[u]);
 41     if(fx[u]<fx[root])    root=u;
 42 }
 43 void getsz(int u,int fa)
 44 {
 45     sz[u]=1;
 46     for(int k=f1[u];k;k=e[k].nxt)
 47         if(!vis[e[k].to]&&e[k].to!=fa)
 48         {
 49             getsz(e[k].to,u);
 50             sz[u]+=sz[e[k].to];
 51         }
 52 }
 53 void getdeep(int u,int fa)
 54 {
 55     s[root].insert(getdis(u,ff[root]));
 56     for(int k=f1[u];k;k=e[k].nxt)
 57         if(!vis[e[k].to]&&e[k].to!=fa)
 58             getdeep(e[k].to,u);
 59 }
 60 char tmp[20];
 61 int getmax2(int p)
 62 {
 63     if(s2[p].size()<2)    return -0x3f3f3f3f;
 64     multiset<int>::reverse_iterator it=s2[p].rbegin();int ans=0;
 65     ans+=*it;++it;ans+=*it;
 66     return ans;
 67 }
 68 void solve(int u)
 69 {
 70     vis[u]=1;
 71     s2[u].insert(0);
 72     for(int k=f1[u];k;k=e[k].nxt)
 73         if(!vis[e[k].to])
 74         {
 75             getsz(e[k].to,0);sum=sz[e[k].to];
 76             root=0;getroot(e[k].to,0);
 77             ff[root]=u;getdeep(root,0);
 78             if(!s[root].empty())    s2[u].insert(*s[root].rbegin());
 79             solve(root);
 80         }
 81     s3.insert(getmax2(u));
 82 }
 83 void dfs1(int u,int fa,int d,int d2)
 84 {
 85     eu[++eu[0]]=u;pos[u]=eu[0];dpx[eu[0]]=d;dpx2[eu[0]]=d2;
 86     for(int k=f1[u];k;k=e[k].nxt)
 87         if(e[k].to!=fa)
 88         {
 89             dfs1(e[k].to,u,d+1,d2+e[k].d);
 90             eu[++eu[0]]=u;
 91             dpx[eu[0]]=d;
 92             dpx2[eu[0]]=d2;
 93         }
 94 }
 95 //void debugxxxx(multiset<int>& s)
 96 //{
 97 //    for(auto i : s)    printf("%d ",i);
 98 //    puts("test");
 99 //}
100 void change(int u)
101 {
102     int now;
103     s3.erase(s3.find(getmax2(u)));
104     if(!fl[u])    s2[u].erase(s2[u].find(0));
105     for(now=u;ff[now];now=ff[now])
106     {
107         s3.erase(s3.find(getmax2(ff[now])));
108         if(!s[now].empty())    s2[ff[now]].erase(s2[ff[now]].find(*s[now].rbegin()));
109         if(!fl[u])    s[now].erase(s[now].find(getdis(u,ff[now])));
110     }
111     fl[u]^=1;
112     if(!fl[u])    s2[u].insert(0);
113     s3.insert(getmax2(u));
114     for(now=u;ff[now];now=ff[now])
115     {
116         if(!fl[u])    s[now].insert(getdis(u,ff[now]));
117         if(!s[now].empty())    s2[ff[now]].insert(*s[now].rbegin());
118         s3.insert(getmax2(ff[now]));
119     }
120 }
121 int num;
122 int main()
123 {
124     lft[0]=1;
125     fx[0]=0x3f3f3f3f;
126     int i,j,a,b,la=0,q,t,c;
127     for(i=1;i<=27;i++)    lft[i]=(lft[i-1]<<1);
128     for(i=1;i<=200000;i++)
129     {
130         if(i>=lft[la+1])    ++la;
131         log2x[i]=la;
132     }
133     scanf("%d",&n);
134     for(i=1;i<n;i++)
135     {
136         scanf("%d%d%d",&a,&b,&c);
137         e[++ne].to=b;e[ne].nxt=f1[a];e[ne].d=c;f1[a]=ne;
138         e[++ne].to=a;e[ne].nxt=f1[b];e[ne].d=c;f1[b]=ne;
139     }
140     dfs1(1,0,0,0);
141     for(i=1;i<=eu[0];i++)    st[i][0]=eu[i];
142     for(j=1;(1<<j)<=eu[0];j++)
143         for(i=1;i+lft[j]-1<=eu[0];i++)
144             if(dpx[pos[st[i][j-1]]]>dpx[pos[st[i+lft[j-1]][j-1]]])
145                 st[i][j]=st[i+lft[j-1]][j-1];
146             else
147                 st[i][j]=st[i][j-1];
148     sum=n;getroot(1,0);
149     solve(root);
150     scanf("%d",&q);
151     num=n;
152     while(q--)
153     {
154         scanf("%s",tmp);
155         if(tmp[0]=='A')
156         {
157             if(num==0)    printf("They have disappeared.
");
158             else if(num==1)    printf("0
");
159             else    printf("%d
",max(*s3.rbegin(),0));
160         }
161         else if(tmp[0]=='C')
162         {
163             scanf("%d",&t);
164             if(fl[t])    num++;else    num--;
165             change(t);
166         }
167     }
168     return 0;
169 }
View Code

数据生成器

var random = Math.random, floor = Math.floor, exit = process.exit, print = console.log;
var n = 100000, q = 100000;
console.log(n);
var fa = new Array(n+1), a, b, ta, tb, idx;
for(i=1; i<=n; i++)    fa[i] = i;
function find(x)    {return x===fa[x]?x:fa[x]=find(fa[x]);}
for(i=1; i<n; i++)    {
    do    {
        a = floor(random()*n) + 1;
        b = floor(random()*n) + 1;
        ta = find(a);tb = find(b);
    }
    while(ta == tb);
    fa[ta] = tb;
    console.log(a+" "+b+" "+(floor(random()*21)-10));
}
console.log(q);
for(i=1; i<=q; i++)    {
    idx = floor(random()*2);
    if (idx === 1)    {
        console.log("A");
    }
    else    {
        console.log("C "+(floor(random()*n)+1));
    }
}
View Code

另有:捉迷藏特殊做法

原文地址:https://www.cnblogs.com/hehe54321/p/8577902.html