洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV
意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次。因此原树上任意一个节点都会出现在点分树上,且是恰好一次
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[];
int f1[],ne;
int ff[],n,sum,fx[],dep[],sz[];
int eu[],pos[],dpx[],st[][],log2x[];
int root;
bool fl[],vis[];
multiset<int> s[],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+],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-(<<k)+][k]]]?st[r-(<<k)+][k]:st[l][k];
return dpx[pos[x]]+dpx[pos[y]]-*dpx[pos[t]];
}
void getroot(int u,int fa)
{
sz[u]=;fx[u]=;
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]=;
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]+;
getdeep(e[k].to,u);
}
}
char tmp[];
int getmax2(int p)
{
if(s[p].size()<) return -0x3f3f3f3f;
auto it=s[p].rbegin();int ans=;
ans+=*it;++it;ans+=*it;
return ans;
}
void solve(int u)
{
vis[u]=;
dep[u]=;getdeep(u,);s2.insert(getmax2(u));
for(int k=f1[u];k;k=e[k].nxt)
if(!vis[e[k].to])
{
getsz(e[k].to,);sum=sz[e[k].to];
root=;getroot(e[k].to,);
ff[root]=u;
solve(root);
}
}
void dfs1(int u,int fa,int d)
{
eu[++eu[]]=u;pos[u]=eu[];dpx[eu[]]=d;
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
dfs1(e[k].to,u,d+);
eu[++eu[]]=u;
dpx[eu[]]=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]^=;
for(now=u;now;now=ff[now])
{
if(!fl[u]) s[now].insert(getdis(u,now));
s2.insert(getmax2(now));
}
}
int main()
{
fx[]=0x3f3f3f3f;
int i,j,a,b,la=,q,t;
for(i=;i<=;i++)
{
if(i>=(<<(la+))) ++la;
log2x[i]=la;
}
scanf("%d",&n);
for(i=;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(,,);
for(i=;i<=eu[];i++) st[i][]=eu[i];
for(j=;(<<j)<=eu[];j++)
for(i=;i+(<<j)-<=eu[];i++)
if(dpx[pos[st[i][j-]]]>dpx[pos[st[i+(<<(j-))][j-]]])
st[i][j]=st[i+(<<(j-))][j-];
else
st[i][j]=st[i][j-];
//getdis(5,4);
sum=n;getroot(,);
solve(root);
scanf("%d",&q);
while(q--)
{
scanf("%s",tmp);
if(tmp[]=='G')
{
printf("%d\n",*s2.rbegin());
}
else if(tmp[]=='C')
{
scanf("%d",&t);
change(t);
}
}
return ;
}
)
最终代码(洛谷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[];
int f1[],ne;
int ff[],n,sum,fx[],sz[];
int eu[],pos[],dpx[],st[][],log2x[],lft[];
int root;
bool fl[],vis[];
multiset<int> s[],s2[],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+],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+][k]]]?st[r-lft[k]+][k]:st[l][k];
    return dpx[pos[x]]+dpx[pos[y]]-*dpx[pos[t]];
}
void getroot(int u,int fa)
{
    sz[u]=;fx[u]=;
    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]=;
    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[];
int getmax2(int p)
{
    if(s2[p].size()<)    return -0x3f3f3f3f;
    multiset<int>::reverse_iterator it=s2[p].rbegin();int ans=;
    ans+=*it;++it;ans+=*it;
    return ans;
}
void solve(int u)
{
    vis[u]=;
    s2[u].insert();
    for(int k=f1[u];k;k=e[k].nxt)
        if(!vis[e[k].to])
        {
            getsz(e[k].to,);sum=sz[e[k].to];
            root=;getroot(e[k].to,);
            ff[root]=u;getdeep(root,);
            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[]]=u;pos[u]=eu[];dpx[eu[]]=d;
    for(int k=f1[u];k;k=e[k].nxt)
        if(e[k].to!=fa)
        {
            dfs1(e[k].to,u,d+);
            eu[++eu[]]=u;
            dpx[eu[]]=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());
    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]^=;
    if(!fl[u])    s2[u].insert();
    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[]=;
    fx[]=0x3f3f3f3f;
    int i,j,a,b,la=,q,t;
    for(i=;i<=;i++)    lft[i]=(lft[i-]<<);
    for(i=;i<=;i++)
    {
        if(i>=lft[la+])    ++la;
        log2x[i]=la;
    }
    scanf("%d",&n);
    for(i=;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(,,);
    for(i=;i<=eu[];i++)    st[i][]=eu[i];
    for(j=;(<<j)<=eu[];j++)
        for(i=;i+lft[j]-<=eu[];i++)
            if(dpx[pos[st[i][j-]]]>dpx[pos[st[i+lft[j-]][j-]]])
                st[i][j]=st[i+lft[j-]][j-];
            else
                st[i][j]=st[i][j-];
    sum=n;getroot(,);
    solve(root);
    scanf("%d",&q);
    num=n;
    while(q--)
    {
        scanf("%s",tmp);
        if(tmp[]=='G')
        {
            if(num==)    printf("-1\n");
            else if(num==)    printf("0\n");
            else    printf("%d\n",*s3.rbegin());
        }
        else if(tmp[]=='C')
        {
            scanf("%d",&t);
            if(fl[t])    num++;else    num--;
            change(t);
        }
    }
    return ;
}
Qtree4卡不过去...算了不卡了,反正对拍没对出错(本地n=100000,q=100000随机数据1.5秒)
 #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,d;
 }e[];
 int f1[],ne;
 int ff[],n,sum,fx[],sz[];
 int eu[],pos[],dpx[],dpx2[],st[][],log2x[],lft[];
 int root;
 bool fl[],vis[];
 multiset<int> s[],s2[],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+],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+][k]]]?st[r-lft[k]+][k]:st[l][k];
     return dpx2[pos[x]]+dpx2[pos[y]]-*dpx2[pos[t]];
 }
 void getroot(int u,int fa)
 {
     sz[u]=;fx[u]=;
     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]=;
     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[];
 int getmax2(int p)
 {
     if(s2[p].size()<)    return -0x3f3f3f3f;
     multiset<int>::reverse_iterator it=s2[p].rbegin();int ans=;
     ans+=*it;++it;ans+=*it;
     return ans;
 }
 void solve(int u)
 {
     vis[u]=;
     s2[u].insert();
     for(int k=f1[u];k;k=e[k].nxt)
         if(!vis[e[k].to])
         {
             getsz(e[k].to,);sum=sz[e[k].to];
             root=;getroot(e[k].to,);
             ff[root]=u;getdeep(root,);
             if(!s[root].empty())    s2[u].insert(*s[root].rbegin());
             solve(root);
         }
     s3.insert(getmax2(u));
 }
 void dfs1(int u,int fa,int d,int d2)
 {
     eu[++eu[]]=u;pos[u]=eu[];dpx[eu[]]=d;dpx2[eu[]]=d2;
     for(int k=f1[u];k;k=e[k].nxt)
         if(e[k].to!=fa)
         {
             dfs1(e[k].to,u,d+,d2+e[k].d);
             eu[++eu[]]=u;
             dpx[eu[]]=d;
             dpx2[eu[]]=d2;
         }
 }
 //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());
     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]^=;
     if(!fl[u])    s2[u].insert();
     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[]=;
     fx[]=0x3f3f3f3f;
     int i,j,a,b,la=,q,t,c;
     for(i=;i<=;i++)    lft[i]=(lft[i-]<<);
     for(i=;i<=;i++)
     {
         if(i>=lft[la+])    ++la;
         log2x[i]=la;
     }
     scanf("%d",&n);
     for(i=;i<n;i++)
     {
         scanf("%d%d%d",&a,&b,&c);
         e[++ne].to=b;e[ne].nxt=f1[a];e[ne].d=c;f1[a]=ne;
         e[++ne].to=a;e[ne].nxt=f1[b];e[ne].d=c;f1[b]=ne;
     }
     dfs1(,,,);
     for(i=;i<=eu[];i++)    st[i][]=eu[i];
     for(j=;(<<j)<=eu[];j++)
         for(i=;i+lft[j]-<=eu[];i++)
             if(dpx[pos[st[i][j-]]]>dpx[pos[st[i+lft[j-]][j-]]])
                 st[i][j]=st[i+lft[j-]][j-];
             else
                 st[i][j]=st[i][j-];
     sum=n;getroot(,);
     solve(root);
     scanf("%d",&q);
     num=n;
     while(q--)
     {
         scanf("%s",tmp);
         if(tmp[]=='A')
         {
             if(num==)    printf("They have disappeared.\n");
             else if(num==)    printf("0\n");
             else    printf("%d\n",max(*s3.rbegin(),));
         }
         else if(tmp[]=='C')
         {
             scanf("%d",&t);
             if(fl[t])    num++;else    num--;
             change(t);
         }
     }
     return ;
 }
数据生成器
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));
}
}
另有:捉迷藏特殊做法
洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV的更多相关文章
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
		
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
 - BZOJ.1095.[ZJOI2007]捉迷藏(线段树 括号序列)
		
BZOJ 洛谷 对树DFS得到括号序列.比如这样一个括号序列:[A[B[E][F[H][I]]][C][D[G]]]. 那比如\(D,E\)间的最短距离,就是将\(D,E\)间的括号序列取出:][[] ...
 - BZOJ 1095: [ZJOI2007]Hide 捉迷藏
		
Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...
 - bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
		
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...
 - 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏
		
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
 - 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$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ...
 
随机推荐
- 【原创】PHP扩展开发入门
			
PHP扩展开发入门 作者:wf (360电商技术组) 在我们编写自己的第一个php扩展之前,先了解一下php的总体架构和执行机制. php的架构如图1所看到的. 当中一个重要的就是SAPI(serve ...
 - 【PostgreSQL】PostgreSQL操作-psql基本命令
			
在阅读的过程中有不论什么问题,欢迎一起交流 邮箱:1494713801@qq.com QQ:1494713801 一.建立数据库连接 ---------------- 接入PostgreSQL数 ...
 - APache POI emaple ()
			
Business Plan The BusinessPlan application creates a sample business plan with three phases, weekly ...
 - 自己定义验证器——用Struts2框架以框架师的思维灵活做好该事情
			
面对的问题:自己定义一个18位身份验证器.编写验证器.在validators.xml文件里进行注冊.在验证配置文件里使用? 第一部分:理解Struts2中自带的验证器 第二部分:如何通过server( ...
 - getifaddrs
			
getifaddrs 获取本地网络接口的信息.在路由器上可以用这个接口来获取wan/lan等接口当前的ip地址,广播地址等信息. #include <sys/types.h> #inclu ...
 - 对于api安全性的思考
			
目前的情况下api被很多地方应用,随之而来的是api的安全性问题. 我所认识到的安全性问题有以下几个方面: 1.DDoS(拒绝服务攻击),接口被恶意调用,使真实的用户无法享受到正常畅通的服务. ...
 - Java SE之break和continue标签
			
文是学习网络上的文章时的总结,感谢大家无私的分享. Java没有提供goto功能,可是保留了gotokeyword. 在java中能够使用break标签和continue标签功能实现简版的goto功能 ...
 - 零基础学python-5.1 数字简单介绍
			
1.创建数值对象并赋值 a=1#整数 b=1.1#浮点数 c=1.23e5#实数 d=1.23+4.56j#虚数 2.更新数值对象 注意:由于数值对象是不可变,所以与其说更新,还不如说把变量名从一个对 ...
 - 用UltraEdit比較两个文件
			
在编写代码的过程中,经常碰到两个文件之间的逐行比較.特别是新代码与源码之间的文字比較,这里介绍用UltraEdit实现新代码与源码之间的比較方法. //源码:Bearing.mac FINISH /C ...
 - python itertools
			
1 product 1.1 一个generator函数 因此它的返回值是一个iterator,可以用for遍历. 1.2 计算product的参数分类 1.2.1 dict和list 只用了dict的 ...