BZOJ1095:Hide 捉迷藏 && SPOJ Qtree IV (树的三分治/括号序列)

题目传送门:
BZOJ1095:http://www.lydsy.com/JudgeOnline/problem.php?id=1095
SPOJ Query on a tree IV vjudge题面:https://cn.vjudge.net/problem/SPOJ-QTREE4#


题目分析:看完题就会发现后面那题是前面那题的加强版。

这两题都可以用链剖,边分和点分实现。前两种解法可以见09年QZC的国集论文,点分的做法可以见PoPoQQQ大爷的blog

前一题因为边权固定为1,还有一种用线段树维护括号序列的做法,见某dalao的blog。线段树维护的东西比较烦,我就没写。

以前在学链剖的时候曾经想过会不会有用这种算法动态维护DP值的题目,今天终于见到了,果然是一道很神的题。至于括号序列之类的,它的性质我很早前就忘了QAQ。

我把点分和链剖的code都写了一遍,写链剖的原因是BZOJ上我动态点分治的AC代码到SPOJ上就TLE了可能是因为我点分写得丑。链剖的常数明显要比动态点分治小很多,据论文里面说“这是因为链的长度和链的个数相互制约”。

两种方法都码了大概1.5h左右,不过链剖好写一些。另外如果不用STL的priority_queue的话,代码长度真的会死人的……

(回去多复习点分治和括号序列)


CODE(动态点分治):

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

const int maxn=100100;
const int maxl=22;
const int oo=1e9;

struct edge
{
    int obj;
    edge *Next;
} e[maxn<<1];
edge *head[maxn];
int cur=-1;

int Mid[maxn][maxl]; //每个点每次被覆盖时的分治中心 
int Fa[maxn][maxl]; //分治时对应的子树的根,自身为分治中心则为0 
int Dep[maxn][maxl]; //分治时离分治中心的距离 
int num[maxn]; //统计次数 

int Size[maxn];
int max_Size[maxn];
int tree[maxn];
int cnt;

struct Heap
{
    priority_queue <int> ins,del;
} ;
Heap dis[maxn][maxl]; //每个点作为分治中心的直接儿子时,存储的所有黑点深度 
Heap max_dis[maxn]; //每个点作为分治中心时,每个子树加它自身的最大深度 
Heap ans; //答案 

vector <int> Son[maxn]; //每个点作为分治中心时的直接儿子 
bool vis[maxn];
int col[maxn];

int n,m;

void Add(int x,int y)
{
    cur++;
    e[cur].obj=y;
    e[cur].Next=head[x];
    head[x]=e+cur;
}

void Dfs(int node,int fa)
{
    tree[++cnt]=node;
    Size[node]=1;
    max_Size[node]=0;

    for (edge *p=head[node]; p; p=p->Next)
    {
        int son=p->obj;
        if ( son==fa || vis[son] ) continue;

        Dfs(son,node);
        Size[node]+=Size[son];
        max_Size[node]=max(max_Size[node],Size[son]);
    }
}

void Work(int node,int fa,int dep,int id,int root)
{
    ++num[node];
    Mid[node][ num[node] ]=root;
    Fa[node][ num[node] ]=id;
    Dep[node][ num[node] ]=dep;
    dis[id][ num[id] ].ins.push(dep);

    for (edge *p=head[node]; p; p=p->Next)
    {
        int son=p->obj;
        if ( son==fa || vis[son] ) continue;
        Work(son,node,dep+1,id,root);
    }
}

int Max(Heap &s)
{
    while ( !s.del.empty() && s.ins.top()==s.del.top() )
        s.ins.pop(),s.del.pop();
    if (s.ins.empty()) return -oo;
    return s.ins.top();
}

int Max2(Heap &s)
{
    int val=Max(s);
    if (val==-oo) return -oo;
    s.ins.pop();
    while ( !s.del.empty() && s.ins.top()==s.del.top() )
        s.ins.pop(),s.del.pop();
    int temp;
    if (s.ins.empty()) temp=-oo;
    else temp=s.ins.top();
    s.ins.push(val);
    return temp;
}

void Solve(int node)
{
    cnt=0;
    Dfs(node,node);
    if (cnt==-1) return;

    int root=tree[1];
    for (int i=1; i<=cnt; i++)
    {
        int x=tree[i];
        max_Size[x]=max(max_Size[x],Size[node]-Size[x]);
        if (max_Size[x]<max_Size[root]) root=x;
    }

    for (edge *p=head[root]; p; p=p->Next)
    {
        int son=p->obj;
        if (vis[son]) continue;

        Son[root].push_back(son);
        Work(son,root,1,son,root);
        max_dis[root].ins.push( Max(dis[son][ num[son] ]) );
    }

    ++num[root];
    Mid[root][ num[root] ]=root;
    max_dis[root].ins.push(0);
    ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );

    vis[root]=true;
    for (int i=0; i<Son[root].size(); i++) Solve(Son[root][i]);
}

void Insert(int node)
{
    for (int i=num[node]; i>=1; i--)
    {
        int root=Mid[node][i];
        if (root==node)
        {
            ans.del.push( Max(max_dis[root])+Max2(max_dis[root]) );
            max_dis[root].ins.push(0);
            ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
        }
        else
        {
            int id=Fa[node][i];
            ans.del.push( Max(max_dis[root])+Max2(max_dis[root]) );
            max_dis[root].del.push( Max(dis[id][i]) );
            dis[id][i].ins.push(Dep[node][i]);
            max_dis[root].ins.push( Max(dis[id][i]) );
            ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
        }
    }
}

void Delete(int node)
{
    for (int i=num[node]; i>=1; i--)
    {
        int root=Mid[node][i];
        if (root==node)
        {
            ans.del.push( Max(max_dis[root])+Max2(max_dis[root]) );
            max_dis[root].del.push(0);
            ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
        }
        else
        {
            int id=Fa[node][i];
            ans.del.push( Max(max_dis[root])+Max2(max_dis[root]) );
            max_dis[root].del.push( Max(dis[id][i]) );
            dis[id][i].del.push(Dep[node][i]);
            max_dis[root].ins.push( Max(dis[id][i]) );
            ans.ins.push( Max(max_dis[root])+Max2(max_dis[root]) );
        }
    }
}

int main()
{
    freopen("1095.in","r",stdin);
    freopen("1095.out","w",stdout);

    scanf("%d",&n);
    for (int i=1; i<=n; i++) head[i]=NULL;
    for (int i=1; i<n; i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        Add(x,y);
        Add(y,x);
    }

    for (int i=1; i<=n; i++) col[i]=1;
    int val=n;
    Solve(1);

    scanf("%d",&m);
    for (int i=1; i<=m; i++)
    {
        char c=getchar();
        while ( c!='G' && c!='C' ) c=getchar();

        if (c=='G')
        {
            if (!val) printf("-1\n");
            if (val==1) printf("0\n");
            if (val>1) printf("%d\n", Max(ans) );
        }
        else
        {
            int x;
            scanf("%d",&x);
            if (!col[x]) Insert(x),val++;
            else Delete(x),val--;
            col[x]^=1;
        }
    }

    return 0;
}

CODE(树链剖分):

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn=100100;
const int oo=1050000000;

struct edge
{
    int obj,len;
    edge *Next;
} e[maxn<<1];
edge *head[maxn];
int cur=-1;

int fa[maxn];
int dep[maxn];
int Size[maxn];
int Son[maxn];

int Top[maxn];
int max_dep[maxn];
int Len[maxn];

int dfn[maxn];
int dfsx[maxn];
int Time=0;

struct Heap
{
    priority_queue <int> ins,del;
} Light[maxn];
Heap ans;

struct Seg
{
    int Lmax,Rmax,opt,sum;
    Seg *Lson,*Rson;
} tree[maxn<<2];
Seg *Root[maxn];
int cnt=-1;

int col[maxn];
int n,m;

void Add(int x,int y,int z)
{
    cur++;
    e[cur].obj=y;
    e[cur].len=z;
    e[cur].Next=head[x];
    head[x]=e+cur;
}

void Dfs1(int node)
{
    Size[node]=1;
    for (edge *p=head[node]; p; p=p->Next)
    {
        int son=p->obj;
        if (son==fa[node]) continue;

        fa[son]=node;
        dep[son]=dep[node]+1;
        Dfs1(son);

        Size[node]+=Size[son];
        if (Size[son]>Size[ Son[node] ]) Son[node]=son;
    }
}

void Dfs2(int node)
{
    dfsx[++Time]=node;
    dfn[node]=Time;
    max_dep[ Top[node] ]=max(max_dep[ Top[node] ],dep[node]);

    int t=Time;
    if (Son[node]) Top[ Son[node] ]=Top[node],Dfs2(Son[node]);

    for (edge *p=head[node]; p; p=p->Next)
    {
        int son=p->obj;
        if (son==Son[node]) Len[t]=p->len;
        if ( son==fa[node] || son==Son[node] ) continue;

        Len[Time]=p->len;
        Top[son]=son;
        Dfs2(son);
    }
}

Seg *New_seg()
{
    cur++;
    return tree+cur;
}

int Max(Heap &s)
{
    while ( !s.del.empty() && s.ins.top()==s.del.top() ) s.ins.pop(),s.del.pop();
    if (s.ins.empty()) return -oo;
    return s.ins.top();
}

int Max2(Heap &s)
{
    int val=Max(s);
    if (val==-oo) return val;
    s.del.push(val);
    int temp=Max(s);
    s.ins.push(val);
    return temp;
}

void Up(Seg *root,int x)
{
    root->Lmax=max(root->Lson->sum+x+root->Rson->Lmax,root->Lson->Lmax);
    root->Rmax=max(root->Rson->sum+x+root->Lson->Rmax,root->Rson->Rmax);
    root->opt=max(root->Lson->opt,root->Rson->opt);
    root->opt=max(root->opt,root->Lson->Rmax+x+root->Rson->Lmax);
}

void Build(Seg *root,int L,int R)
{
    if (L==R)
    {
        int node=dfsx[L];
        root->Lmax=root->Rmax=Max(Light[node]);
        root->opt=root->Lmax+Max2(Light[node]);
        root->sum=0;
        return;
    }

    int mid=(L+R)>>1;
    root->Lson=New_seg();
    Build(root->Lson,L,mid);
    root->Rson=New_seg();
    Build(root->Rson,mid+1,R);

    Up(root,Len[mid]);
    root->sum=root->Lson->sum+root->Rson->sum+Len[mid];
}

void DP(int node)
{
    Light[node].ins.push(0);
    for (edge *p=head[node]; p; p=p->Next)
    {
        int son=p->obj;
        if (son==fa[node]) continue;
        DP(son);
        if (son!=Son[node]) Light[node].ins.push(Root[son]->Lmax+p->len);
    }
    if (node==Top[node])
    {
        Root[node]=New_seg();
        Build(Root[node],dfn[node],dfn[node]-dep[node]+max_dep[node]);
        ans.ins.push(Root[node]->opt);
    }
}

void Update(Seg *root,int L,int R,int x)
{
    if (L==R)
    {
        int node=dfsx[L];
        root->Lmax=root->Rmax=Max(Light[node]);
        root->opt=root->Lmax+Max2(Light[node]);
        return;
    }

    int mid=(L+R)>>1;
    if (x<=mid) Update(root->Lson,L,mid,x);
    else Update(root->Rson,mid+1,R,x);
    Up(root,Len[mid]);
}

void Work(int node,int id)
{
    if (id) Light[node].ins.push(0);
    else Light[node].del.push(0);
    while (node)
    {
        int up=Top[node];
        ans.del.push(Root[up]->opt);
        if (fa[up]) Light[ fa[up] ].del.push( Root[up]->Lmax+Len[ dfn[up]-1 ] );

        Update(Root[up],dfn[up],dfn[up]-dep[up]+max_dep[up],dfn[node]);
        if (fa[up]) Light[ fa[up] ].ins.push( Root[up]->Lmax+Len[ dfn[up]-1 ] );
        ans.ins.push(Root[up]->opt);
        node=fa[up];
    }
}

int main()
{
    freopen("1095.in","r",stdin);
    freopen("1095.out","w",stdout);

    scanf("%d",&n);
    for (int i=1; i<=n; i++) head[i]=NULL;
    for (int i=1; i<n; i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        Add(x,y,z);
        Add(y,x,z);
    }

    dep[1]=1;
    Dfs1(1);
    Top[1]=1;
    Dfs2(1);
    DP(1);

    int val=n;
    for (int i=1; i<=n; i++) col[i]=1;
    scanf("%d",&m);
    for (int i=1; i<=m; i++)
    {
        char c=getchar();
        while ( c!='A' && c!='C' ) c=getchar();
        if (c=='A')
            if (!val) printf("They have disappeared.\n");
            else if (val==1) printf("0\n");
                 else printf("%d\n", max(0, Max(ans)) ); //!!!
        else
        {
            int x;
            scanf("%d",&x);
            if (col[x]) Work(x,0),val--;
            else Work(x,1),val++;
            col[x]^=1;
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值