Luogu P5658 括號樹 搜尋 遞推

2022-06-02 02:54:12 字數 1347 閱讀 5557

csp2019 s組d1t2

題目鏈結

題目大意:一棵樹上每個節點有(或),根到每個節點的路徑可形成一括號串,求根到每個節點形成的括號串的合法括號字串個數,取異或和。

解析:該題為csp2019提高組容易拿分的一道。選擇寫鏈是個不錯選擇(然後我就這裡打掛了 70pts),正解其實在考場上也能想出。

子串說明要連續,而我們接好乙個括號後它顯然可以接上前面連續的括號序列。

即:設乙個節點\(x\)的答案為\(ans_x\),設此次接的左括號位置\(y\),則\(ans_x+=ans_y+1\)(因為自己單獨也算乙個)。而乙個節點的父親節點的答案,也會在該節點中原封不動的展現,故應加上節點的所有父親節點之答案。

我們採用\(dfs\)演算法遍歷整棵樹,遇到節點為左括號進棧,否則在棧中匹配乙個還沒有匹配的左括號,成功匹配,則按上面累加答案。

這裡有乙個問題,即從\(dfs\)退出時,我們在這裡的東西需銷毀,這同時牽涉到上面左括號的匹配。因此,這裡採用\(vis\)來維護上述。若該節點為左括號,則結束搜尋時將該節點退出棧。否則取消該節點匹配的左括號的已匹配狀態,然後退出搜尋。

具體解析見**。

#includeusing namespace std;

int cc,to[600000],net[600000],fr[600000],fa[600000],zhan[600000],t,n,nt[600000];

long long s[600000];

char ch[600000];string st;bool vis[600000];

void addedge(int u,int v)

void dfs1(int x)//匹配括號

//壓棧

else

if (nt[x])

//匹配左括號

} for (int i=fr[x];i;i=net[i])

//往下繼續找

if (ch[x]=='(')

t--;

else vis[zhan[nt[x]]]=false;//還原陣列

}void dfs2(int x)//起累加父親節點答案作用

}int main()

bool lian=true;

for (int i=2;i<=n;i++)

//建樹

//到這裡原始答案已全部求出

long long ans=s[1];

for (int i=2;i<=n;i++)

cout《附:鏈的部分分**(其實與正解中統計答案相似)

if (lian)

else

}for (int i=1;i<=n;i++)

}

P5658 括號樹 貪心

miku so crazy 因為把stack的型別寫成bool 把自己搞自閉了 思路,顯然如果乙個點是 那麼不會有貢獻,只要壓入佇列,答案繼承父親就行了 如果是 如果能匹配,就判斷 的父親是什麼,如果是 那麼顯然把根節點到 的父親的序列中與剛匹配的 相接的部分加上剛匹配的 也是合法的 不考慮剛匹配的...

洛谷 P5658 括號樹(DFS)

通過資料範圍可以發現,這個題的複雜度要控制在o n o nlogn 之間。所以對於每一次處理,需要o logn 甚至o 1 對於o 1 的處理,可以直接想一下找規律 如果乙個右括號能匹配左括號,且左括號的前乙個括號是乙個已經匹配了的右括號,那麼就可以將這兩個序列合併,當前右括號的貢獻等於前乙個右括號...

CSP S 2019 洛谷P5658 括號樹

本題中合法括號串的定義如下 是合法括號串。如果a是合法括號串,則 a 是合法括號串。如果a,b是合法括號串,則ab是合法括號串。本題中子串與不同的子串的定義如下 4.字串s的子串是s中連續的任意個字元組成的字串。s的子串可用起始位置 l 與終止位置 r 來表示,記為 s l,r 1 leq l le...