Gym 101142G Gangsters in Central City【思维+Lca】

题意:

  • 给一棵树,叶子节点为房子,q次操作,节点1为根节点(蓄水池)向房子供水
  • 每次操作有两种类型,+ x 强盗占领了编号为x的房子,- x强盗离开了编号为x的房子。
  • 对每次操作,ans1计算出最少卡住几个节点使得强盗占领的房子都没水喝,ans2卡住这些点后没有被强盗占领的房子通不了水的数量最小,每次输出这两个数

思路:

  • 对根节点,如果有k个直接连接的点,拆成k棵子树。每棵有强盗占领的子树肯定最多只需要卡住一个点,那ans1就是k个子树中有强盗的的子树数量。
  • 对每棵子树求出被强盗占领的点dfs序最大的和最小的两个点的lca就是这棵子树中被强盗占领的所有的点的lca。处理出每个节点下有多少个房子(sz[i]),那么求出lca后,先减去没进行这次操作前这个子树的贡献,然后再加上这个操作,求出这颗子树上的点的lca,再加上这棵子树的贡献。ans2=sz[lca]-强盗占领的点

代码:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t) for(int i=(s);i<(t);++i)
#define per(i,s,t) for(int i=((t)-1);i>=(s);--i)
#define pb push_back
#define dd(x) cout<<#x<<'='<<x<<' '
#define de(x) cout<<#x<<'='<<x<<'\n'
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
const int N=1e6+5;
int dp[N][20],n;
vi G[N];
set<int>st[N]; //维护第i棵子树中的dfs序
int tot,ver[N*2],R[N*2],First[N*2],bel[N],sz[N],cut[N];
 //cut[i] 第i棵子树中强盗占领的房子数量 
//bel[i],节点i属于那棵子数
// First[u] u节点的在ver中第一次出现的下标,即dfs序
bool vis[N];
void dfs(int u,int dep){
    vis[u]=true;ver[++tot]=u;First[u]=tot;R[tot]=dep;
    rep(i,0,G[u].size()){
        int v=G[u][i];
        if(!vis[v]){
            dfs(v,dep+1);
            ver[++tot]=u;
            R[tot]=dep;
        }
    }
}
void ST(){
    rep(i,1,tot+1){
        dp[i][0]=i;
    }
    for(int j=1;(1<<j)<=tot;++j){
        for(int i=1;i+(1<<j)-1<=tot;++i){
            int a=dp[i][j-1];http://codeforces.com/group/aUVPeyEnI2/contest/229510/attachments
            int b=dp[i+(1<<(j-1))][j-1];
            if(R[a]<R[b])dp[i][j]=a;
            else dp[i][j]=b;
        }
    }
}
int RMQ(int l,int r){
    int k=0;
    while(1<<(k+1)<=r-l+1){
        k++;
    }
    int a=dp[l][k],b=dp[r-(1<<k)+1][k];
    return R[a]<R[b]?a:b;
}
int LCA(int u,int v){
    int res=RMQ(u,v);
    return ver[res];
}
void Dfs(int u,int rt){
    bel[u]=rt;
    vis[u]=true;
    if(G[u].size())sz[u]=0;
    else sz[u]=1;
    rep(i,0,G[u].size()){
        int v=G[u][i];
        if(!vis[v]){
            Dfs(v,rt);
            sz[u]+=sz[v];
        }
    }
}
int main()
{
    tot=0;
    memset(vis,0,sizeof(vis));
    memset(sz,0,sizeof(sz));
    int q,p;
    scanf("%d%d",&n,&q);
    rep(i,2,n+1){
        scanf("%d",&p);
        G[p].pb(i);
    }
    dfs(1,1);
    ST();
    memset(vis,0,sizeof(vis));
    rep(i,0,G[1].size()){
        Dfs(G[1][i],i+1);
    }
    int ans1=0,ans2=0;
    char op[10];
    int x,fa,mi,ma,lca;
    while(q--){
          scanf("%s%d",op,&x);
          if(op[0]=='+'){
                fa=bel[x];
                if(cut[fa]){
                    mi=*st[fa].begin(),ma=*st[fa].rbegin();
                    lca=LCA(mi,ma);
                    ans2-=sz[lca]-cut[fa];
                }
                if(cut[fa]==0)ans1++;
                cut[fa]++;
                st[fa].insert(First[x]);
                mi=*st[fa].begin(),ma=*st[fa].rbegin();
                lca=LCA(mi,ma);
                ans2+=sz[lca]-cut[fa];
          }
          else{
                fa=bel[x];
                mi=*st[fa].begin(),ma=*st[fa].rbegin();
                lca=LCA(mi,ma);
                ans2-=sz[lca]-cut[fa];
                if(cut[fa]==1)ans1--;
                cut[fa]--;
                st[fa].erase(First[x]);
                if(cut[fa]){
                    mi=*st[fa].begin(),ma=*st[fa].rbegin();
                    lca=LCA(mi,ma);
                    ans2+=sz[lca]-cut[fa];
                }
          }
          printf("%d %d\n",ans1,ans2);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/PinappleMi/article/details/82985058
今日推荐