Gym 101142G Gangsters in Central City【思維+Lca】
阿新 • • 發佈:2018-12-14
題意:
- 給一棵樹,葉子節點為房子,q次操作,節點1為根節點(蓄水池)向房子供水
- 每次操作有兩種型別,+ x 強盜佔領了編號為x的房子,- x強盜離開了編號為x的房子。
- 對每次操作,ans1計算出最少卡住幾個節點使得強盜佔領的房子都沒水喝,ans2卡住這些點後沒有被強盜佔領的房子通不了水的數量最小,每次輸出這兩個數
思路:
- 對根節點,如果有k個直接連線的點,拆成k棵子樹。每棵有強盜佔領的子樹肯定最多隻需要卡住一個點,那ans1就是k個子樹中有強盜的的子樹數量。
- 對每棵子樹求出被強盜佔領的點dfs序最大的和最小的兩個點的lca就是這棵子樹中被強盜佔領的所有的點的lca。處理出每個節點下有多少個房子(sz[i]
程式碼:
#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;
}