1. 程式人生 > >Codeforces Round #316 (Div. 2) D. Tree Requests(DFS+狀態壓縮)

Codeforces Round #316 (Div. 2) D. Tree Requests(DFS+狀態壓縮)

back push_back init data cti pragma [0 ack false

題意:給定一棵樹,n個節點。每一個節點處有一個字母,結點的深度定義為節點到根結點1的距離,

有m個詢問(u。v),每次回答以結點u為根的子樹的深度為v的那些節點處的字母是否能組成一個回文串,特別的,空串也是回文串。


思路:首先說明推斷回文串的方法,僅僅要出現次數為奇數個字母個數不超過2。那麽這些字母一定能夠組成回文串。


接下來考慮將樹轉成線性結構。

利用dfs+時間戳將結點依照深度存入一個線性結構裏,Depth[i]數組裏存的是深度為i的全部結點,

那麽對於詢問有三種情況。一種是dep[u]>=v輸出Yes

另外一種是desdep[u]<v(以結點u為根的子樹中的最大節點深度),輸出Yes

剩余情況為第三種,比較復雜也是我們要解決的問題


由於以結點u為根的深度為v的結點在Dep[v]數組中下標肯定是連續的,

所以利用時間戳兩次二分找到以結點u為根的深度為v的結點在Dep[v]數組中的起始下標ql和截止下標qr,

由於我們僅僅須要推斷每一個字母是否出現奇數次,所以我們能夠用一個長26位的狀態表示每一個字母出現奇數次還是偶數次,

並且這種話這個狀態具有一個非常優美的性質,能夠通過異或來轉移狀態

那麽這樣我們僅僅須要預處理出每一個深度的前綴的狀態su[dep][i]就可以,

推斷時僅僅需推斷su[dep][qr] xor su[dep][ql-1]中有多少位為1就可以,

若一的位數小於2輸出Yes,否則輸出No。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii (pair<int, int>)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int maxn = 500000+1000;
//const int INF = 0x3f3f3f3f;
vector<int> G[maxn];
vector<int> Depth[maxn], su[maxn];
int w[maxn];
int dep[maxn], tim[maxn][2], desdep[maxn];
int n, m, clock_cnt;
char str[maxn];

void dfs(int cur) {
    desdep[cur] = dep[cur];
	tim[cur][0] = ++clock_cnt;
	for(int i = 0; i < G[cur].size(); i++) {
		int u = G[cur][i];
		dep[u] = dep[cur] + 1;
		Depth[dep[u]].push_back(u);
		dfs(u);
		desdep[cur] = max(desdep[cur], desdep[u]);
	}
	tim[cur][1] = ++clock_cnt;
}

void init() {
	int d = 1;
	while(1) {
		int sz = Depth[d].size();
		if(!sz) break;
		for(int i = 0; i < sz; i++) {
			int t = w[Depth[d][i]];
			int tmp = su[d][i];
			su[d].push_back(tmp^(1<<t));
		}
		d++;
	}
}

bool check(int dep, int ql, int qr) {
	int palin = su[dep][qr]^su[dep][ql];
	int cnt = 0;
	for(int i = 0; i < 26; i++) {
		if((1<<i)&palin) cnt++;
	}
	if(cnt>1) return false;
	return true;
}

int main() {
    //freopen("input.txt", "r", stdin);
	while(scanf("%d%d", &n, &m) == 2) {
		for(int i = 1; i <= n; i++) G[i].clear(), Depth[i].clear(), su[i].clear();
		for(int i = 1; i <= n; i++) su[i].push_back(0);
		clock_cnt = 0;
		for(int i = 2; i <= n; i++) {
			int t; scanf("%d", &t);
			G[t].push_back(i);
		}
		Depth[1].push_back(1), dep[1] = 1;
		scanf("%s", str);
		for(int i = 1; i <= n; i++) w[i] = str[i-1]-'a';
		dfs(1);
		init();
		//for(int i = 1; i <= n; i++) cout << tim[i][0] << " " << tim[i][1] << endl;
		for(int i = 0; i < m; i++) {
			int u, v; scanf("%d%d", &u, &v);
			if(dep[u] >= v) printf("Yes\n");
			else if(desdep[u] < v) printf("Yes\n");
			else {
				int ql, qr;
				int L = 0, R = Depth[v].size()-1;
				while(L < R) {
					int M = (L+R)>>1;
					int tmp = Depth[v][M];
					if(tim[tmp][0] > tim[u][0]) R = M;
					else L = M+1;
				}
				ql = R;
				L = 0, R = Depth[v].size()-1;
				while(L <= R) {
					int M = (L+R)>>1;
					int tmp = Depth[v][M];
					if(tim[tmp][1] > tim[u][1]) R = M-1;
					else L = M+1;
				}
				qr = R;
				if(check(v, ql, qr+1)) printf("Yes\n");
				else printf("No\n");
			}
		}
	}
    return 0;
}









Codeforces Round #316 (Div. 2) D. Tree Requests(DFS+狀態壓縮)