POJ 数据结构(3)
数据结构 |
trie图的建立和应用,DFA |
hdd2222,poj1204, poj2778, poj3691 |
LCA和RMQ问题 |
poj1330 |
|
双端队列和它的应用 |
poj2823(单调队列) |
|
左偏树 |
poj3666,poj3016 |
|
后缀树,后缀数组 |
poj2758 |
trie图的建立和应用,DFA
hdu2222
很裸的题,可以作为模板:
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <ctime> #include <queue> #include <map> #include <sstream> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) const int eps = 1e-6; const int inf = ~0u>>2; typedef long long LL; using namespace std; class Node { public: Node* fail; Node* next[26]; int cnt; Node() { CL(next, 0); fail = NULL; cnt = 0; } }; //Node* q[10000000]; class AC_automaton : public Node{ public: Node *root; int head, tail; void init() { root = new Node(); head = tail = 0; } void insert(char* st) { Node* p = root; while(*st) { if(p->next[*st-'a'] == NULL) { p->next[*st-'a'] = new Node(); } p = p->next[*st-'a']; st++; } p->cnt++; } void build() { root->fail = NULL; deque<Node* > q; q.push_back(root); while(!q.empty()) { Node* tmp = q.front(); Node* p = NULL; q.pop_front(); for(int i = 0; i < 26; ++i) { if(tmp->next[i] != NULL) { if(tmp == root) tmp->next[i]->fail = root; else { p = tmp->fail; while(p != NULL) { if(p->next[i] != NULL) { tmp->next[i]->fail = p->next[i]; break; } p = p->fail; } if(p == NULL) tmp->next[i]->fail = root; } q.push_back(tmp->next[i]); } } } } int search(char* st) { int cnt = 0, t; Node* p = root; while(*st) { t = *st - 'a'; while(p->next[t] == NULL && p != root) { p = p->fail; } p = p->next[t]; if(p == NULL) p = root; Node* tmp = p; while(tmp != root && tmp->cnt != -1) { cnt += tmp->cnt; tmp->cnt = -1; tmp = tmp->fail; } st++; } return cnt; } }AC; char dic[100], st[1000010]; int main() { freopen("data.in", "r", stdin); int t, n, ans; scanf("%d", &t); while(t--) { scanf("%d", &n); AC.init(); while(n--) { scanf("%s", dic); AC.insert(dic); } AC.build(); scanf("%s", st); ans = AC.search(st); cout << ans << endl; } return 0; }
poj 1204
题意是给一个字符串矩阵。然后给一些模式串,问这个模式串在矩阵的哪个位置被找到(可以从矩阵中的某个点向八个方向扩展)。。。输出开始坐标和方向。
解:用trie图写的,看得gw老师的课件。。。对模式串反向建trie图就可以,好蛋疼的是模式串为
ABC
ABCDEF
这种形式。。。需要加一个vector记录危险节点为A的所有串的编号。。。
从早晨一直搞。。。终于搞过了,拍了近4.5k的代码。。。
详见代码:
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <ctime> #include <queue> #include <map> #include <sstream> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) const int eps = 1e-6; const int inf = ~0u>>2; typedef long long LL; using namespace std; const int N = 1024; const int LET = 26; int nNodesCount = 0; struct CNode { CNode * ch[LET]; CNode * pPre; vector<int> bstopNode; int num; CNode() { CL(ch, 0); bstopNode.clear(); pPre = NULL; } }; CNode T[100000]; char mp[N][N]; int r, c, m; bool vis[N] = {false}; int dir[8][2] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}}; void insert(CNode* p, char* s, int x) { int i, l = strlen(s); for(i = l - 1; i >= 0; --i) { if(p->ch[s[i]-'A'] == NULL) { p->ch[s[i]-'A'] = T + nNodesCount++; } p = p->ch[s[i] - 'A']; } p->bstopNode.push_back(x); } void buildDFA() { int i; for(i = 0; i < LET; ++i) { T[0].ch[i] = T + 1; } T[0].pPre = NULL; T[1].pPre = T; deque<CNode *> q; q.push_back(T + 1); while(!q.empty()) { CNode * proot = q.front(); q.pop_front(); for(i = 0; i < LET; ++i) { CNode* p = proot->ch[i]; if(p) { CNode* father = proot->pPre; while(father) { if(father->ch[i]) { p->pPre = father->ch[i]; if(p->pPre->bstopNode.size() != 0) { vector<int>::iterator it; for(it = p->pPre->bstopNode.begin(); it != p->pPre->bstopNode.end(); ++it) p->bstopNode.push_back(*it); } break; } else father = father->pPre; } q.push_back(p); } } } } bool inmap(int x, int y) { if(x < 0 || x >= r || y < 0 || y >= c) return false; return true; } struct node { int x, y; char c; node() {} node(int a, int b, char d) : x(a), y(b), c(d) {} } ans[10000]; bool search(int sx, int sy, int d) { CNode* p = T + 1; int x, y; for(x = sx, y = sy; inmap(x, y); x += dir[d][0], y += dir[d][1]) { while(true) { if(p->ch[mp[x][y] - 'A']) { p = p->ch[mp[x][y] - 'A']; if(p->bstopNode.size() != 0) { //printf("%d %d %d\n", x, y, p->num); vector<int>::iterator it; for(it = p->bstopNode.begin(); it != p->bstopNode.end(); ++it) if(!vis[*it]) { ans[*it] = node(x, y, (d + 4)%8 + 'A'); vis[*it] = true; } //return true; } break; } else p = p->pPre; } } return false; } void solve() { buildDFA(); int i; for(i = 0; i < r; ++i) { search(i, 0, 2); search(i, 0, 1); search(i, 0, 3); search(i, c - 1, 6); search(i, c - 1, 5); search(i, c - 1, 7); } for(i = 0; i < c; ++i) { search(0, i, 4); search(0, i, 5); search(0, i, 3); search(r - 1, i, 0); search(r - 1, i, 1); search(r - 1, i, 7); } } int main() { //freopen("data.in", "r", stdin); int i; scanf("%d%d%d", &r, &c, &m); for(i = 0; i < r; ++i) { scanf("%s", mp[i]); } char st[N]; nNodesCount = 2; for(i = 0; i < m; ++i) { scanf("%s", st); insert(T + 1, st, i); } solve(); for(i = 0; i < m; ++i) { printf("%d %d %c\n", ans[i].x, ans[i].y, ans[i].c); } return 0; }
poj 2278&&3691
http://www.cnblogs.com/vongang/archive/2012/11/06/2756422.html
LCA和RMQ问题
poj 1330
题意很裸,就是求LCA。
LCA转化为RMQ的方法:http://www.cnblogs.com/vongang/archive/2012/05/03/2481196.html
RMQ写搓了。。。wa了3次。。。
谨记!
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <ctime> #include <queue> #include <map> #include <sstream> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) x < y ? x : y #define Max(x, y) x < y ? y : x #define E(x) (1 << (x)) const int eps = 1e-6; const int inf = ~0u>>2; typedef long long LL; using namespace std; const int N = 20010; int D[N], E[N], R[N]; class RMQ { public: int Min[N][20]; void build(int n) { int i, j, m; for(i = 1; i <= n; ++i) Min[i][0] = i; m = int(log(double(n))/log(2.0)); FOR(j, 1, m) { FOR(i, 1, n - (1<<j) + 1) { if(D[Min[i][j-1]] < D[Min[i+(1<<(j-1))][j-1]]) { Min[i][j] = Min[i][j-1]; } else { Min[i][j] = Min[i+(1<<(j-1))][j-1]; } } } } int query(int s, int e) { int k = log(double(e - s + 1))/log(2.0); if(D[Min[s][k]] < D[Min[e-(1<<k) + 1][k]]) return Min[s][k]; else return Min[e-(1<<k) + 1][k]; } } Q; vector<int> g[N]; int in[N], cnt; bool vis[N]; void init(int n) { CL(in, 0); CL(D, 0); CL(E, 0); CL(R, 0); CL(vis, 0); cnt = 1; for(int i = 1; i <= n; ++i) { g[i].clear(); } } void dfs(int t, int dep) { if(!vis[t]) { R[t] = cnt; vis[t] = true; } D[cnt] = dep; E[cnt++] = t; for(int i = 0; i < int(g[t].size()); ++i) { dfs(g[t][i], dep + 1); D[cnt] = dep; E[cnt++] = t; } } int main() { //freopen("data.in", "r", stdin); int t, i, n, x, y; scanf("%d", &t); while(t--) { scanf("%d", &n); init(n); REP(i, n - 1) { scanf("%d%d", &x, &y); g[x].push_back(y); in[y]++; } FOR(i, 1, n) { if(in[i] == 0) { dfs(i, 0); break; } } cnt--; Q.build(cnt); scanf("%d%d", &x, &y); x = R[x], y = R[y]; if(x > y) swap(x, y); printf("%d\n", E[Q.query(x, y)]); } return 0; }
双端队列和它的应用
poj 2823 (单调队列)
单调队列的原理是双端队列,好吧,我只能说这个标题没有错。。。
单调队列的思想是保证窗口的元素的value是从前往后是依次减小(增大)的。还有一个值就是当前value的position,也就是说窗口里所有元素的position都必须跟当前待插入的元素的position的距离相差小于等于窗口的大小。(-_-! 说的好别扭)
// 单调队列模板 const int N = 1000010; class Node { public: int pos; int num; Node() {}; Node(int _a, int _b) : pos(_a), num(_b) {} }; class Dequ{ Node deq[N]; public: void Get_Min(int ans[], int _num[], int n, int k) { int i, head, tail; head = tail = 0; REP(i, n) { if(head < tail && deq[head].pos <= i - k) head++; while(head < tail && deq[tail-1].num >= _num[i]) tail--; deq[tail++] = Node(i, _num[i]); ans[i] = deq[head].num; } } void Get_Max(int ans[], int _num[], int n, int k) { int i, head, tail; head = tail = 0; REP(i, n) { if(head < tail && deq[head].pos <= i - k) head++; while(head < tail && deq[tail-1].num <= _num[i]) tail--; deq[tail++] = Node(i, _num[i]); ans[i] = deq[head].num; } } } Dequeue;
左偏树
poj 3666
只知道dp的解法。。。左偏树维护中位数真心没看懂。。
先对序列排下序,用排好序的下标代表那个数(算是离散化吧)。
dp[i[[j] 到第i个位置,高度为[1...j]中任意一个的最小花费。
dp[i][j] = dp[i-1][j] + iabs(A[j] - A[i]) if(j > 0) dp[i][j] = min(dp[i][j-1], dp[i][j];