字典树

来源:互联网 发布:驾考预约软件 编辑:程序博客网 时间:2024/06/05 10:45

poj 3764 The xor-longest Path
题意:给定一棵树,问你最长的异或路径。

思路:想到LCA就差不多了,我们记录根到节点i路径的ans[i]
这样对于u>v路径的异或值为ans[u]ans[v]
相当于给定n1个数,求解max(两两异或的最大值, 单个的最大值)。

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <string>#include <cstring>#include <map>#include <vector>#include <queue>#include <stack>#include <set>#include <cstdlib>#define ll o<<1#define rr o<<1|1#define CLR(a, b) memset(a, (b), sizeof(a))using namespace std;typedef long long LL;typedef pair<int, int> pii;const int MAXN = 1e5 + 10;const int INF = 1e9 + 10;const double PI = acos(-1.0);const double eps = 1e-6;const int MOD = 1e9 + 7;void add(LL &x, LL y) { x += y; x %= MOD; }struct Edge {    int from, to, val, next;};Edge edge[MAXN * 2];int head[MAXN], edgenum;void addEdge(int u, int v, int w) {    Edge E = {u, v, w, head[u]};    edge[edgenum] = E;    head[u] = edgenum++;}int Next[31 * MAXN][2], word[31 * MAXN], L, root;int f[40];int newnode() {    Next[L][0] = Next[L][1] = -1;    word[L++] = 0;    return L - 1;}void init() { L = 0; root = newnode(); }void Insert(int val) {    int u = root;    for(int i = 30; i >= 0; i--) {        int v = (val & f[i]) ? 1 : 0;        if(Next[u][v] == -1) {            Next[u][v] = newnode();        }        u = Next[u][v];        word[u]++;    }}int Query(int val) {    int ans = 0; int u = root;    for(int i = 30; i >= 0; i--) {        int v = (val & f[i]) ? 1 : 0;        if(v == 0) {            if(Next[u][1] != -1 && word[Next[u][1]]) {                ans ^= f[i]; u = Next[u][1];            }            else {                u = Next[u][0];            }        }        else {            if(Next[u][0] != -1 && word[Next[u][0]]) {                ans ^= f[i]; u = Next[u][0];            }            else {                u = Next[u][1];            }        }    }    return ans;}int val[MAXN];void DFS(int u, int fa) {    for(int i = head[u]; i != -1; i = edge[i].next) {        int v = edge[i].to;        if(v == fa) continue;        val[v] = val[u] ^ edge[i].val;        DFS(v, u);    }}int main(){    f[0] = 1;    for(int i = 1; i <= 30; i++) {        f[i] = f[i - 1] * 2;    }    int n;    while(scanf("%d", &n) != EOF) {        for(int i = 1; i <= n; i++) head[i] = -1, val[i] = 0;        edgenum = 0;        for(int i = 1; i <= n - 1; i++) {            int u, v, w; scanf("%d%d%d", &u, &v, &w);            u++; v++;            addEdge(u, v, w); addEdge(v, u, w);        }        DFS(1, -1); init(); int ans = 0;        for(int i = 2; i <= n; i++) {            Insert(val[i]);            ans = max(ans, val[i]);        }        for(int i = 2; i <= n; i++) {            ans = max(Query(val[i]), ans);        }        printf("%d\n", ans);    }    return 0;}

lightoj 1269 - Consecutive Sum

题意:给你连续子序列的最大异或值和最小异或值。
维护前缀异或和即可。

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <string>#include <cstring>#include <map>#include <vector>#include <queue>#include <stack>#include <set>#include <cstdlib>#define ll o<<1#define rr o<<1|1#define CLR(a, b) memset(a, (b), sizeof(a))using namespace std;typedef long long LL;typedef pair<int, int> pii;const int MAXN = 5e4 + 10;const int INF = 1e9 + 10;const double PI = acos(-1.0);const double eps = 1e-6;const int MOD = 1e9 + 7;void add(LL &x, LL y) { x += y; x %= MOD; }struct Edge {    int from, to, val, next;};Edge edge[MAXN * 2];int head[MAXN], edgenum;void addEdge(int u, int v, int w) {    Edge E = {u, v, w, head[u]};    edge[edgenum] = E;    head[u] = edgenum++;}int Next[31 * MAXN][2], word[31 * MAXN], L, root;int f[40];int newnode() {    Next[L][0] = Next[L][1] = -1;    word[L++] = 0;    return L - 1;}void init() { L = 0; root = newnode(); }void Insert(int val) {    int u = root;    for(int i = 30; i >= 0; i--) {        int v = (val & f[i]) ? 1 : 0;        if(Next[u][v] == -1) {            Next[u][v] = newnode();        }        u = Next[u][v];        word[u]++;    }}int Query_Max(int val) {    int u = root;    for(int i = 30; i >= 0; i--) {        int v = (val & f[i]) ? 1 : 0;        if(v == 0) {            if(Next[u][1] != -1 && word[Next[u][1]]) {                val ^= f[i]; u = Next[u][1];            }            else {                u = Next[u][0];            }        }        else {            if(Next[u][0] != -1 && word[Next[u][0]]) {                u = Next[u][0];            }            else {                val ^= f[i]; u = Next[u][1];            }        }    }    return val;}int Query_Min(int val) {    int u = root;    for(int i = 30; i >= 0; i--) {        int v = (val & f[i]) ? 1 : 0;        if(v == 1) {            if(Next[u][1] != -1 && word[Next[u][1]]) {                val ^= f[i]; u = Next[u][1];            }            else {                u = Next[u][0];            }        }        else {            if(Next[u][0] != -1 && word[Next[u][0]]) {                u = Next[u][0];            }            else {                val ^= f[i]; u = Next[u][1];            }        }    }    return val;}int main(){    f[0] = 1;    for(int i = 1; i <= 30; i++) {        f[i] = f[i - 1] * 2;    }    int t, kcase = 1; scanf("%d", &t);    while(t--) {        int n; scanf("%d", &n);        init(); int ans1 = 0, ans2 = (int)((1LL << 31) - 1);        int sum = 0;        for(int i = 1; i <= n; i++) {            int v; scanf("%d", &v); sum ^= v;            if(i > 1) {                ans1 = max(Query_Max(sum), ans1);                ans2 = min(Query_Min(sum), ans2);            }            Insert(sum);            ans1 = max(sum, ans1);            ans2 = min(sum, ans2);        }        printf("Case %d: %d %d\n", kcase++, ans1, ans2);    }    return 0;}

hdoj 5715 XOR 游戏
有毒。。。
字典树节点Next[u][0]=1一直WA,找了一小时bug,发现改成Next[u][0]=0莫名AC?

思路:考虑二分答案,这样就变成了判定性问题。
对于当前的答案o,我们只要证明n个数分m段后所有段最小值大于o即可。
即有dp[i][j]i个数分j段对于答案o是否合法。
dp[i][j]=(sum[k]sum[i]>=o)(iL<=k<i&&dp[k][j1]==true)

每次在字典树上插入合法的dp[k][j1],然后就是判断在所有合法的dp[k][j1]里面是否存在一个k使得sum[k]sum[i]>=oiL<=k<i
那样就是求解异或sum[i]后的最大值了。

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <string>#include <cstring>#include <map>#include <vector>#include <queue>#include <stack>#include <set>#include <cstdlib>#define ll o<<1#define rr o<<1|1#define CLR(a, b) memset(a, (b), sizeof(a))using namespace std;typedef long long LL;typedef pair<int, int> pii;const int MAXN = 1e4 + 10;const int INF = 1e9 + 10;const double PI = acos(-1.0);const double eps = 1e-6;const int MOD = 1e9 + 7;void add(LL &x, LL y) { x += y; x %= MOD; }int f[31];struct Trie {    int Next[31 * MAXN][2], word[31 * MAXN], L, root;    int newnode() {        Next[L][0] = Next[L][1] = 0; word[L++] = 0;        return L - 1;    }    void init() { L = 0; root = newnode(); }    void Insert(int val) {        int u = root;        for(int i = 30; i >= 0; i--) {            int v = (val & f[i]) ? 1 : 0;            if(Next[u][v] == 0) {                Next[u][v] = newnode();            }            u = Next[u][v];            word[u]++;        }    }    void Delete(int val) {        int u = root;        for(int i = 30; i >= 0; i--) {            int v = (val & f[i]) ? 1 : 0;            u = Next[u][v];            word[u]--;        }    }    int Query(int val) {        int u = root, ans = 0;        for(int i = 30; i >= 0; i--) {            int v = (val & f[i]) ? 1 : 0;            if(Next[u][v ^ 1] != 0 && word[Next[u][v ^ 1]]) {                ans ^= f[i]; u = Next[u][v ^ 1];            }            else {                u = Next[u][v];            }        }        return ans;    }}; Trie trie[11];bool dp[MAXN][11];int sum[MAXN];int N, M, L;bool judge(int o) {    for(int i = 0; i <= M; i++) {        trie[i].init();    }    for(int i = 0; i <= N; i++) {        for(int j = 0; j <= M; j++) {            dp[i][j] = false;        }    }    trie[0].Insert(sum[0]); dp[0][0] = true;    for(int i = 1; i <= N; i++) {        for(int j = M; j >= 1; j--) {            if(i - L > 0) {                if(dp[i - L - 1][j - 1]) {                    trie[j - 1].Delete(sum[i - L - 1]);                }            }            if(trie[j - 1].Query(sum[i]) >= o) {                dp[i][j] = true;                trie[j].Insert(sum[i]);            }        }    }    return dp[N][M];}int main(){    f[0] = 1;    for(int i = 1; i <= 30; i++) {        f[i] = f[i - 1] * 2;    }    int t, kcase = 1; scanf("%d", &t);    while(t--) {        scanf("%d%d%d", &N, &M, &L);        sum[0] = 0;        for(int i = 1; i <= N; i++) {            int v; scanf("%d", &v);            sum[i] = sum[i - 1] ^ v;        }        int l = 0, r = (1 << 30) - 1;        int ans = 0;        while(r >= l) {            int mid = l + r >> 1;            if(judge(mid)) {                ans = mid;                l = mid + 1;            }            else {                r = mid - 1;            }        }        printf("Case #%d:\n%d\n", kcase++, ans);    }    return 0;}

几道水题
lightoj 1114 - Easily Readable

lightoj 1129 - Consistency Checker

lightoj 1224 - DNA Prefix
这道题有点意思吧,n个串中选出任意个。问max(串数目 * 公共前缀长度)
就相当于把串扫一遍,统计最小覆盖。中间要加个特判剪枝。

0 0