1. 程式人生 > >2016-2017 ACM-ICPC, NEERC, Northern Subregional Contest G

2016-2017 ACM-ICPC, NEERC, Northern Subregional Contest G

題目大意

現有一顆有根樹,葉子節點可被染成黑色(最開始都是白色),也可以被染回白色,現在問給出每次染色資訊後(即帶修改),最少需要切斷幾條邊保證黑色葉子不在樹上,且在此條件下最少有多少白色葉子不在樹上。

解題思路

大體演算法:DFS序+倍增
很容易發現,被切斷的邊數最多隻需要與根節點相連的邊數,因為根節點連出去的每顆子樹最多隻需要一條邊就可以切斷,所以每顆子樹都是獨立的。
這樣問題就轉化為了找出每課子樹中被染黑的葉子節點的最近公共祖先,多個點的LCA我發現可以用DFS序+倍增在O(logN)找出(沒百度到相關解法,自己YY加上hzh提示想出來的)

具體實現:
從根出發dfs,dfs的時候需要維護四個東西:1.時間戳,dfn[]記錄訪問時間,low[]記錄子樹中最晚訪問的點的dfn[];2.f[][],倍增方法記錄祖先;3.siz[]統計子樹中葉子節點的個數;4.所屬子樹編號
然後對每顆子樹建立一個大根堆和小根堆,維護一顆子樹中黑色葉子dfn的最大值maxx和最小值minn,因為還要帶刪除,如果用用優先佇列還需要一個輔助陣列。然後從一個黑色葉子節點出發,用倍增找出最近公共祖先,條件是(dfn[fa] <= minn && low[fa] >= maxx),找到LCA後,再利用利用siz陣列,很容易得出答案

~~~程式碼比較醜

#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int maxn = 100010;
const int lg = 20;

int f[maxn][lg];
int n,q;
int pre_ans[maxn];
int pre_cnt[maxn];
int siz[maxn],cnt;
int x,index = 1;
char c;
int dfn[maxn],low[maxn],p[maxn];
bool co[maxn];
struct edge
{
    int v,next;
}e[maxn << 1];
int h[maxn],num;
int pos_cnt = 0;
struct node_max
{
    int pos,x;
    node_max(int _pos,int _x)
    {
        pos = _pos;
        x = _x;
    }
    friend bool operator< (node_max a,node_max b)
    {
        return a.x < b.x;
    }
};
struct node_min
{
    int pos,x;
    node_min(int _pos,int _x)
    {
        pos = _pos;
        x = _x;
    }
    friend bool operator< (node_min a,node_min b)
    {
        return a.x > b.x;
    }
};

priority_queue<node_max>qmax[maxn];
priority_queue<node_min>qmin[maxn];

void build_edge(int u,int v)
{
    num++;
    e[num].v = v;
    e[num].next = h[u];
    h[u] = num;
}

void dfs(int x,int pos,int fa)
{
    dfn[x] = ++index;
    p[x] = pos;
    f[x][0] = fa;
    for(int i = 1; i < lg; i++)
        f[x][i] = f[f[x][i-1]][i-1];
    for(int i = h[x]; i; i = e[i].next)
    {
        dfs(e[i].v,pos,x);
        siz[x] += siz[e[i].v];
    }
    low[x] = index;
    if(low[x] == dfn[x])
        siz[x] = 1;
}

bool inqueue_max[maxn];
bool inqueue_min[maxn];

int getRoot(int x)
{
    if(pre_cnt[x] == 0)
        return 0;
    while(!qmax[x].empty())
    {
        if(!co[qmax[x].top().x])
            inqueue_max[qmax[x].top().x] = false,qmax[x].pop();
        else
            break;
    }
    while(!qmin[x].empty())
    {
        if(!co[qmin[x].top().x])
            inqueue_min[qmin[x].top().x] = false,qmin[x].pop();
        else
            break;
    }
    int maxx,minn,u;
    maxx = qmax[x].top().x;
    minn = qmin[x].top().x;
    u = qmax[x].top().pos;
    if(pre_cnt[x] == 1)
        return u;
    for(int i = lg - 1; i >= 0; i--)
        while(dfn[f[u][i]] > minn || low[f[u][i]] < maxx)
            u = f[u][i];
    return f[u][0];
}

int main()
{
    freopen("gangsters.in","r",stdin);
    freopen("gangsters.out","w",stdout);
    scanf("%d%d",&n,&q);
    for(int i = 2; i <= n; i++)
    {
        scanf("%d",&x);
        build_edge(x,i);
    }
    dfn[1] = 1, dfn[0] = 0;
    low[1] = n, low[0] = 9999999;
    for(int i = h[1]; i; i = e[i].next)
    {
        pos_cnt++;
        dfs(e[i].v,pos_cnt,1);
        siz[1] += siz[e[i].v];
    }
    int ans_cnt = 0;
    int ans_edge = 0;
    int now_ans;
    int root;
    while(q--)
    {
        scanf(" %c%d",&c,&x);
        if(c == '+')
        {
            pre_cnt[p[x]]++;
            if(pre_cnt[p[x]] == 1)
                ans_edge++;
            co[dfn[x]] = true;
            if(!inqueue_max[dfn[x]])
                qmax[p[x]].push(node_max(x,dfn[x]));
            else
                inqueue_max[dfn[x]] = false;
            if(!inqueue_min[dfn[x]])
                qmin[p[x]].push(node_min(x,dfn[x]));
            else
                inqueue_min[dfn[x]] = false;
        }
        else
        {
            co[dfn[x]] = false;
            pre_cnt[p[x]]--;
            if(pre_cnt[p[x]] == 0)
                ans_edge--;
            inqueue_max[dfn[x]] = true;
            inqueue_min[dfn[x]] = true;

        }
        root = getRoot(p[x]);
        now_ans = siz[root] - pre_cnt[p[x]];
        ans_cnt += now_ans - pre_ans[p[x]];
        pre_ans[p[x]] = now_ans;
        printf("%d %d\n",ans_edge,ans_cnt);
    }
    return 0;
}

相關推薦

2016-2017 ACM-ICPC, NEERC, Northern Subregional Contest G

題目大意 現有一顆有根樹,葉子節點可被染成黑色(最開始都是白色),也可以被染回白色,現在問給出每次染色資訊後(即帶修改),最少需要切斷幾條邊保證黑色葉子不在樹上,且在此條件下最少有多少白色葉子不在樹上。 解題思路 大體演算法:DFS序+倍增 很容易發現,

2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest G.Grand Test (Gym 101612G) 題解

2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest G.Grand Test 題解題目連結題意題解程式碼 題目連結 題意 在一個圖中找兩個點,使這兩個點之間有三條不相交路徑,並輸出這三條路徑。 題解

Codeforces 2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror)

人生的第一次ACM啊(雖然是映象)… 先來一張臨時組建隊伍GZC的合影: 開始的時候Chongkan迷之手氣直接抽H,敲掉了最水的一道題(各種WA),於是從一臉懵逼的蒟蒻我手中接過了A題,說些什麼我聽不懂的東西,然後就去敲了… [Kanosword

2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest (Gym - 101612H)H - Hidden Supervisors(貪心)

題目連結:http://codeforces.com/gym/101612/attachments 題目大意:給出一個有n個結點,且為若干個聯通塊組成的圖,同時保證每個聯通塊都是一棵有根樹。現在要你將這若干個聯通塊連邊(只能由根節點向別的聯通塊連邊),使得只剩下一個聯通塊,同時這個聯通塊也是有根

2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest (Gym

題目大意:給出一個有n個結點,且為若干個聯通塊組成的圖,同時保證每個聯通塊都是一棵有根樹。現在要你將這若干個聯通塊連邊(只能由根節點向別的聯通塊連邊),使得只剩下一個聯通塊,同時這個聯通塊也是有根樹,而且要使得樹內的相連二元組儘可能的多(樹上的點每個點只能屬於一個相連二元

2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest

SDUT 2017 Autumn Team Contest 19th 題解彙總 [Gym-101612I] [Problem I] I - Intelligence in Perpendicularia 計算在多邊形內部可以看到,但在外部看不到的線條長度

2016-2017 ACM-ICPC Northeastern European Regional Contest (NEERC 16)

tor ont freopen n) 物理 sca scanf 圖片 can D:上下界費用流 將每個點和每個長度D的區間看作邊,限制條件看作流量上下界,差分建圖,無源匯最大費用費用流,非常巧妙的使用了差分建圖。 #include<iostream> #in

D. Dog Show 2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest, qualification stage (Online Mirror, ACM-ICPC Rules, Teams Preferred)

cto long space 。。 urn ext team south cpc http://codeforces.com/contest/847/problem/D 巧妙的貪心 仔細琢磨。。。 像凸包裏的處理 1 #include <cstdio>

2017-2018 ACM-ICPC, NEERC, Northern Subregional ContestG - Grand Test

題意:找三條同起點同終點的不相交的路徑 題解:用tarjan的思想,記錄兩個low表示最小和次小的dfs序,以及最小和次小的位置,如果次小的dfs序比dfn小,那麼說明有兩條返祖邊,那麼就是滿足條件的答案 //#pragma GCC optimize(2) //#pragma GCC optimize(3)

2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest B - Byteland Trip dp

B - Byteland Trip 題目大意:給你一個由'<' 和 '>'組成的串, 如果在'<' 只能前往編號比它小的任意點, 反之只能前往比它大的任意點,問你能遍歷所有點 並且每個點只走一次終點在各個位置的方案數。 思路:感覺這種右能從左邊跑到右邊又跑回來的dp很難搞,如果我們確定

2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest

leak infinite odin clas rep nal history play com 地址 Rank Solved A B C D E F G H I J 51/298 6/10 O . O O . . O O O . O: 當場通過 ?:

2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest H - Hilarious Cooking [Gym/101611]

H - Hilarious Cooking [Gym/101611] 題面 思路 考慮序列中已經放置的最近的一組數 a ,

2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest F - Fake or Leak? [Gym/101611]

F - Fake or Leak? [Gym/101611] 題面 思路 算是需要小貪心的模擬題吧 如果輸入輸出簡單一點 可能就是一個銅牌的簽到題吧 對於一個不在給定終榜的隊伍,如果他能滾榜到給定終榜的第一個人上面,那就讓他上去,不然就讓他留在原地,這樣是最能滿足條件的

101611G God of Winds 思路思路思路 2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest

題意: 給定一個n*m的網格,每跳邊有一個初始值,在一些格子裡填數,會對這個格子的4條邊有影響 問是否存在填數方案使得所有的邊值為0; 思路: 對於每一列格子的橫邊,若是加和為0,那一定存在一種

2017-2018 ACM-ICPC, NEERC, Moscow Subregional Contest F

F - Fake or Leak? [Gym/101611] 題面 思路 算是需要小貪心的模擬題吧 如果輸入輸出簡單一點 可能就是一個銅牌的簽到題吧 對於一個不在給定終榜的隊伍,如果他能滾榜到給定終榜的第一個人上面,那就讓他上去,不然就讓他留在原地,這樣是最能

2015-2016 ACM-ICPC, NEERC, Moscow Subregional Contest A題:Anagrams [打表/規律題]

題意:給出一個進位制B ,有一數字K,K的所有倍數,記為Xi , 對於Xi 在B進位制下長度相等的所有數,記為Yi , 若都能被K整除,則這個K叫做B-stable,求所有B-stable; 範圍:N<=20億 解法:觀察資料,發現有一定規律,打表發現所有數都是B-1

【2015-2016 ACM-ICPC, NEERC, Southern Subregional Contest B】【暴力雙排序】Layer Cake 若干矩形 選擇相同長和寬的最大體積

Dasha decided to bake a big and tasty layer cake. In order to do that she went shopping and boughtnrectangular cake layers. The length and the width of t

2016-2017 ACM-ICPC Asia-Bangkok Regional Contest

In icp eof sizeof IE CA esp str lose G:矩陣快速冪 首先找規律,發現數量規律是一個斐波拉契數列,長度為k的串,長度為f(k+1)。之後求[L,R]區間內的和,於是可以想到利用矩陣快速冪求前綴和,將2*2的斐波拉契數列系數矩陣增加一維求和

2016-2017 ACM-ICPC Northeastern European Regional Contest Problem E. Expect to Wait

ref 來源 cmp codeforce ima ring ons clas reg 題目來源:http://codeforces.com/group/aUVPeyEnI2/contest/229509 時間限制:2s 空間限制:512MB 題目大意: 在一個車站中有若幹人

#dp# 2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage

K. Medians and Partition Description: 將一組數恰好分割成多組數,對每組數進行排序後,使得每組數的中位數大於等於m,求解最多可以分成多少組數 Solution: ok[i][j]: 在 [i, j] 這段區間裡的中位數是否符合要求,即