bzoj刷题记录4.10-4.14

bzoj刷题记录4.10-4.14


bzoj1093: [ZJOI2007]最大半联通子图

仍然缩点。缩完点之后每个半联通子图就相当于一条带权链(权值是一个scc的点数)。之后dp即可。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005, MAXM = 2000005;
struct g {
    struct node {
        int to, next;
    } edge[MAXM];
    int head[MAXN], top;
    g(){ top = 0, memset(head, 0, sizeof head); }
    void push(int i, int j)
    { edge[++top] = (node) {j, head[i]}, head[i] = top; }
}g, g1;

int dfn[MAXN], low[MAXN], stk[MAXN], top = 0, dft = 0;
int gp[MAXN], gtop = 0, gsiz[MAXN], vis[MAXN], n, m;

void tarjan(int nd)
{
    dfn[nd] = low[nd] = ++dft;
    stk[++top] = nd, vis[nd] = 1;
    for (int i = g.head[nd]; i; i = g.edge[i].next) {
        int to = g.edge[i].to;
        if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]);
        else if (vis[to]) low[nd] = min(low[nd], dfn[to]);
    }
    if (dfn[nd] == low[nd]) {
        int now; ++gtop;
        do {
            now = stk[top--], vis[now] = 0, gp[now] = gtop, gsiz[gtop]++;
        } while (now != nd);
    }
}

long long x;

set<pair<int,int> > hst;

int dp[MAXN], cnt[MAXN];

int dfs(int nd)
{
    if (dp[nd] != -1) return dp[nd];
    dp[nd] = gsiz[nd];
    for (int i = g1.head[nd]; i; i = g1.edge[i].next)
        dp[nd] = max(dp[nd], dfs(g1.edge[i].to)+gsiz[nd]);
    return dp[nd];
}

int dfs_cnt(int nd)
{
    if (cnt[nd] != -1) return cnt[nd];
    if (!g1.head[nd]) return 1%x;
    cnt[nd] = 0;
    for (int i = g1.head[nd]; i; i = g1.edge[i].next) {
        int to = g1.edge[i].to;
        if (dp[nd] == dp[to] + gsiz[nd]) (cnt[nd] += dfs_cnt(to)) %= x;
    }
    return cnt[nd];
}

void work()
{
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    for (int i = 1; i <= n; i++)
        for (int j = g.head[i]; j; j = g.edge[j].next) {
            int to = g.edge[j].to;
            if (gp[i] != gp[to] && !hst.count(make_pair(gp[i], gp[to]))) {
                hst.insert(make_pair(gp[i], gp[to]));
                g1.push(gp[to], gp[i]); // G^R
            }
        }
    memset(dp, -1, sizeof dp), memset(cnt, -1, sizeof cnt);
    int ans1; long long ans2; ans1 = ans2 = 0;
    for (int i = 1; i <= gtop; i++)
        ans1 = max(ans1, dfs(i));
    for (int i = 1; i <= gtop; i++)
        if (dfs(i) == ans1)
            (ans2 += dfs_cnt(i)) %= x;
    printf("%d\n%lld\n", ans1, ans2);
}
int main()
{
    scanf("%d%d%lld", &n, &m, &x);
    for (int i = 1; i <= m; i++) {
        int u, v; scanf("%d%d", &u, &v), g.push(u, v);
    }
    work();
    return 0;
}

bzoj2208: [JSOI2010] 联通数

缩点后暴力可过..
但是貌似有更好的算法??比如在拓扑图上随意dfs一棵生成树然后dfs序维护??
尚不清楚复杂度是否更优。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 2005, MAXM = MAXN*MAXN;
struct graph {
    struct node {
        int to, next;
    } edge[MAXM];
    int head[MAXN], top;
    graph(){top = 0, memset(head, 0, sizeof head); }
    void push(int i, int j)
    { ++top, edge[top] = (node) {j, head[i]}, head[i] = top; }
} g, g1;

int dfn[MAXN], dft = 0, low[MAXN], vis[MAXN];
int stk[MAXN], top = 0;
int gp[MAXN], gtop = 0, gsiz[MAXN], n;

void tarjan(int nd)
{
    vis[nd] = 1, dfn[nd] = low[nd] = ++dft, stk[++top] = nd;
    for (int i = g.head[nd]; i; i = g.edge[i].next) {
        int to = g.edge[i].to;
        if (!dfn[to]) tarjan(to), low[nd] = min(low[nd], low[to]);
        else if (vis[to]) low[nd] = min(low[nd], dfn[to]);
    }
    if (dfn[nd] == low[nd]) {
        int now; ++gtop; //printf(" -- Group %d --\n", gtop);
        do {
            now = stk[top--];
            gp[now] = gtop, gsiz[gtop]++, vis[now] = 0;
            // cerr << now << " ";
        } while(now != nd); //puts("");
    }
}

int bfstime = 0;
queue<int> que;
int lkt[MAXN][MAXN];

void work()
{
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    for (int i = 1; i <= n; i++)
        for (int j = g.head[i]; j; j = g.edge[j].next) {
            int to = g.edge[j].to;
            if (gp[to] != gp[i] && !lkt[gp[i]][gp[to]]) {
                lkt[gp[i]][gp[to]] = 1;
                g1.push(gp[i], gp[to]);
            }
        }
    int ans = 0;
    memset(vis, 0, sizeof vis);
    for (int i = 1; i <= gtop; i++) {
        ++bfstime;
        que.push(i), vis[i] = bfstime;
        int cnt = 0;
        while (!que.empty()) {
            int t = que.front(); que.pop(), cnt += gsiz[t];
            for (int i = g1.head[t]; i; i = g1.edge[i].next) {
                int to = g1.edge[i].to;
                if (vis[to] != bfstime)
                    vis[to] = bfstime, que.push(to);
            }
        }
        ans += cnt*gsiz[i];
    }
    cout << ans << endl;
}

char str[2005];
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%s", str+1);
        for (int j = 1; j <= n; j++)
            if (str[j] == '1')
                g.push(i, j);
    }
    work();
    return 0;
}

4.11 更新

今天来一波字符串。

bzoj3172: [Tjoi2013]单词

这个题就比较神了。首先建出AC自动机,然后先求出每个节点的“顺着路过的总数 dp[nd] ”,也就是trie树上子树finish标记的总数;然后每个节点表示的串出现的次数就是某个节点fail树的子树中所有 dp[nd] 的总和。

第一次做反了…
形如

sher
shers
her

的数据可以hack。因为shers不会算入her中去。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 3000005;
int chl[MAXN][26], fail[MAXN], fin[MAXN], top = 0, root = 0;
vector<int> ids[MAXN];
int new_node()
{ return ++top, fail[top] = fin[top] = 0, memset(chl[top],0, sizeof chl[top]), top; }

void push(int &nd, const char *str, int id)
{
    if (nd == 0) nd = new_node();
    if (*str == '\0') fin[nd]++, ids[nd].push_back(id);
    else push(chl[nd][*str-'a'], str+1, id);
}

struct node {
    int to, next;
} edge[MAXN];
int head[MAXN], tp_edge = 0;
void push(int i, int j)
{ ++tp_edge, edge[tp_edge] = (node) {j, head[i]}, head[i] = tp_edge; }
int siz[MAXN], n;

queue<int> que;
void init()
{
    que.push(root); fail[root] = 0;
    while (!que.empty()) {
        int t = que.front(); que.pop();
        for (int i = 0; i < 26; i++) if (chl[t][i]) {
            int p = fail[t];
            while (p && !chl[p][i]) p = fail[p];
            if (!p) fail[chl[t][i]] = root;
            else fail[chl[t][i]] = chl[p][i];
            que.push(chl[t][i]);
            push(fail[chl[t][i]], chl[t][i]);
        }
    }
}

long long res[MAXN];
long long dp[MAXN];

int dfs(int nd)
{
    if (siz[nd] != -1) return siz[nd];
    siz[nd] = dp[nd];
    for (int i = head[nd]; i; i = edge[i].next) {
        int to = edge[i].to;
        siz[nd] += dfs(to);
    }
    return siz[nd];
}

long long dfs2(int nd)
{
    if (dp[nd] != -1) return dp[nd];
    dp[nd] = fin[nd];
    for (int i = 0; i < 26; i++)
        if (chl[nd][i])
            dp[nd] += dfs2(chl[nd][i]);
    return dp[nd];
}

char str[MAXN];

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%s", str);
        push(root, str, i);
    }
    init();
    memset(siz, -1, sizeof siz);
    memset(dp, -1, sizeof dp);
    dfs2(root);
    dfs(root);
    for (int i = 1; i <= top; i++)
        for (int j = 0; j < fin[i]; j++)
            res[ids[i][j]] = siz[i];
    for (int i = 1; i <= n; i++)
        printf("%lld\n", res[i]);
    return 0;
}

bzoj1090: [SCOI2003]字符串折叠

首先 |S|100 告诉我们必然不是什么高端结构…

区间dp是正解,方程容易想到,唯一的字符串trick就是用hashk判断相等。

特别注意取某一区间hash的小技巧。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 105;
char str[MAXN];
int n;
unsigned long long hash_tab[MAXN], pwr[MAXN];

unsigned long long hash_val(int i, int j)
{ return hash_tab[j]-hash_tab[i-1]*pwr[j-i+1]; }

int dp[MAXN][MAXN];

int len(int num)
{ return num <= 9 ? 1 : (num <= 99 ? 2 : 3); }

int dfs(int i, int j)
{
    if (dp[i][j] != -1) return dp[i][j];
    if (i == j) return 1;
    dp[i][j] = INT_MAX;
    for (int k = i; k < j; k++)
        dp[i][j] = min(dp[i][j], dfs(i,k)+dfs(k+1,j));
    for (int k = 1; k <= j-i+1; k++) { // 枚举每一块长度
        if ((j-i+1)%k != 0) continue;
        int flag = 1; unsigned long long val = 0;
        for (int p = 0; p < (j-i+1)/k; p++) {
            if (p == 0) val = hash_val(i+p*k, i+(p+1)*k-1);
            else if (val != hash_val(i+p*k, i+(p+1)*k-1)) { flag = 0; break; }
        }
        if (flag) dp[i][j] = min(dp[i][j], dfs(i, i+k-1)+2+len((j-i+1)/k));
    }
    return dp[i][j];
}
int main()
{
    scanf("%s", str+1), n = strlen(str+1);
    pwr[0] = 1;
    for (int i = 1; i <= n; i++) pwr[i] = pwr[i-1]*31;
    for (int i = 1; i <= n; i++) hash_tab[i] = hash_tab[i-1]*31+(str[i]-'A'+1);
    memset(dp, -1, sizeof dp);
    cout << dfs(1, n) << endl;
    return 0;
}

bzoj2124: 等差子序列

乍一看和字符串毫无关系…
事实上,存在一个等差数列当且仅当存在三个点 i<j<k ,满足:

ai=aj+d,ak=ajd

然后对于这种对称的处理思路就两种:

  1. FFT
  2. 回文串

FFT貌似不太好处理,但回文串很兹瓷啊。用线段树记录每个点是否存在1/2并维护区间哈希,然后正反算哈希判断是不是相等即可。如果在某一时刻 i ai两侧不对称,就必然有一段回文串,也就有等差数列。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 10005;
unsigned long long hash_tab[MAXN*4], hash_rev[MAXN*4], power[MAXN];
int lc[MAXN*4], rc[MAXN*4], l[MAXN*4], r[MAXN*4], top = 0, root = 0;
int n, a[MAXN];

inline int siz(int nd) { return r[nd]-l[nd]+1; }
void build(int &nd, int opl, int opr)
{
    nd = ++top, hash_tab[nd] = hash_rev[nd] = 1, lc[nd] = rc[nd] = 0, l[nd] = opl, r[nd] = opr;
    if (opl < opr) {
        build(lc[nd], opl, (opl+opr)/2), build(rc[nd], (opl+opr)/2+1, opr);
        hash_tab[nd] = hash_tab[lc[nd]]+power[siz(lc[nd])]*hash_tab[rc[nd]];
        hash_rev[nd] = hash_rev[rc[nd]]+power[siz(rc[nd])]*hash_rev[lc[nd]];
    }
}
void modify(int nd, int pos)
{
    if (l[nd] == r[nd]) hash_tab[nd] = hash_rev[nd] = 2;
    else {
        modify(pos<=(l[nd]+r[nd])/2?lc[nd]:rc[nd], pos);
        hash_tab[nd] = hash_tab[lc[nd]]+power[siz(lc[nd])]*hash_tab[rc[nd]];
        hash_rev[nd] = hash_rev[rc[nd]]+power[siz(rc[nd])]*hash_rev[lc[nd]];
    }
}
unsigned long long query(int nd, int opl, int opr)
{
    if (l[nd] == opl && r[nd] == opr) return hash_tab[nd];
    else {
        int mid = (l[nd]+r[nd])/2;
        if (opr <= mid) return query(lc[nd], opl, opr);
        else if (opl > mid) return query(rc[nd], opl, opr);
        else return query(lc[nd], opl, mid)+power[mid-opl+1]*query(rc[nd], mid+1, opr);
    }
}
unsigned long long query_reversed(int nd, int opl, int opr)
{
    if (l[nd] == opl && r[nd] == opr) return hash_rev[nd];
    else {
        int mid = (l[nd]+r[nd])/2;
        if (opr <= mid) return query_reversed(lc[nd], opl, opr);
        else if (opl > mid) return query_reversed(rc[nd], opl, opr);
        else return power[opr-mid]*query_reversed(lc[nd], opl, mid)+query_reversed(rc[nd], mid+1, opr);
    }
}
void init()
{
    scanf("%d", &n);
    top = root = 0;
    build(root, 1, n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
}
int main()
{
    int T; scanf("%d", &T);
    power[0] = 1;
    for (int i = 1; i <= 10000; i++) power[i] = power[i-1]*31;
    while (T--) {
        init();
        int flag = 0;
        for (int i = 1; i <= n; i++) {
            // cerr << query(root, 1, 3) << "--" << query_reversed(root, 1, 3) << endl;
            if (a[i] <= n-a[i]+1) {
                if (i >= 2 && i < n && query(root, 1, 2*a[i]-1) != query_reversed(root, 1, 2*a[i]-1)) {
                    flag = 1; break;
                }
            } else {
                int k = 2*(n-a[i]+1)-1;
                if (i >= 2 && i < n && query(root, n-k+1, n) != query_reversed(root, n-k+1, n)) {
                    flag = 1; break;
                }
            }
            modify(root, a[i]);
        }
        if (flag) puts("Y");
        else puts("N");
    }
    return 0;
}

bzoj3207: 花神的嘲讽计划Ⅰ

首先 k20 就可以暴力算出来每个块的哈希,然后就变成一个在区间内有没有某个值的问题了。莫队可解, O(nn) 但跑比谁都快。

注意:hash一定要用ull…

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 400005, lgn = 20;
int n, m, k, bas, sqr;

unsigned long long hash_val(int a[], int l, int r)
{
    unsigned long long ans = 0;
    for (int i = l; i <= r; i++)
        ans = ans*bas+a[i];
    return ans;
}

struct query {
    int l, r, dat, id, ans;
    friend bool operator < (const query &a, const query &b)
    { return a.l/sqr != b.l/sqr ? a.l < b.l : a.r < b.r; }
} q[MAXN];

bool cmp(const query &a, const query &b)
{ return a.id < b.id; }
int a[MAXN], tmp[30];
unsigned long long d[MAXN], dx[MAXN], qu[MAXN], top = 0;
void dx_init()
{
    memcpy(dx, d, sizeof d);
    sort(dx+1, dx+top+1);
}
int dx_num(unsigned long long dat)
{ return lower_bound(dx+1, dx+top+1, dat)-dx; }

int tab[MAXN];

int main()
{
    scanf("%d%d%d", &n, &m, &k), bas = n+1;
    sqr = sqrt(n); // 分块大小
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i+k-1 <= n; i++) d[++top] = hash_val(a, i, i+k-1);
    for (int i = 1; i <= m; i++) {
        scanf("%d%d", &q[i].l, &q[i].r); q[i].r = q[i].r-k+1;
        for (int j = 1; j <= k; j++) scanf("%d", &tmp[j]);
        qu[i] = hash_val(tmp, 1, k);
        d[++top] = qu[i], q[i].id = i;
    }
    dx_init(); // 离散化
    for (int i = 1; i+k-1 <= n; i++) a[i] = dx_num(d[i]);
    for (int i = 1; i <= m; i++) q[i].dat = dx_num(qu[i]);
    sort(q+1, q+m+1);
    memset(tab, 0, sizeof tab);
    int L = q[1].l, R = q[1].r;
    for (int i = L; i <= R; i++) tab[a[i]]++; q[1].ans = tab[q[1].dat];
    for (int i = 2; i <= m; i++) {
        if (q[i].l > q[i].r) continue;
        while (L < q[i].l) tab[a[L++]]--;
        while (L > q[i].l) tab[a[--L]]++;
        while (R < q[i].r) tab[a[++R]]++;
        while (R > q[i].r) tab[a[R--]]--;
        q[i].ans = tab[q[i].dat];
    }
    sort(q+1, q+m+1, cmp);
    for (int i = 1; i <= m; i++)
        if (q[i].ans) puts("No");
        else puts("Yes");
    return 0;
}

bzoj1103: [POI2007]大都市meg

看题解dfs序+树状数组就水过去了, O(nlgn)
但是写了链剖 O(nlg2n) 也水过去了。
然而 O(nlgn) 的lct却死超死超的…
玄学啊…当然也可能我写跪了…

链剖

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 250005;

int C[MAXN], n, dstop = 0;
int lowbit(int i) { return i&(-i); }
void modify(int pos, int dt)
{ for (int i = pos; i <= n; i += lowbit(i)) C[i] += dt; }
int sum(int pos)
{
    int ans = 0;
    for (int i = pos; i > 0; i -= lowbit(i)) { ans += C[i];}
    return ans;
}
int sum(int l, int r)
{ return sum(r)-sum(l-1); }

struct node {
    int to, next;
} edge[MAXN*2];
int head[MAXN], top;
void push(int i, int j)
{ ++top, edge[top] = (node){j, head[i]}, head[i] = top; }

int siz[MAXN], id[MAXN], ind[MAXN], fa[MAXN];

void dfs1(int nd)
{
    siz[nd] = 1;
    for (int i = head[nd]; i; i = edge[i].next)
        dfs1(edge[i].to), siz[nd] += siz[edge[i].to], fa[edge[i].to] = nd;
}

void dfs2(int nd, int from = 0)
{
    id[nd] = ++dstop, ind[nd] = from, modify(id[nd], 1);
    int hev = 0;
    for (int i = head[nd]; i; i = edge[i].next)
        if (siz[edge[i].to] > siz[hev])
            hev = edge[i].to;
    if (!hev) return;
    dfs2(hev, from);
    for (int i = head[nd]; i; i = edge[i].next)
        if (edge[i].to != hev)
            dfs2(edge[i].to, edge[i].to);
}

void change(int nd)
{ modify(id[nd], -1); }

int ask(int nd)
{
    int ans = 0;
    while (nd) {
        // cout << nd << endl;
        ans += sum(id[ind[nd]], id[nd]), nd = fa[ind[nd]];
    }
    return ans;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v; scanf("%d%d", &u, &v);
        if (u > v) swap(u,v);
        push(u, v);
    }
    dfs1(1), dfs2(1);
    int m; scanf("%d", &m);
    for (int i = 1; i <= m+n-1; i++) {
        char s; int u, v;
        scanf("\n%c", &s);
        if (s == 'A') { scanf("%d%d", &u, &v), change(max(u,v)); }
        else if (s == 'W') {scanf("%d", &u), printf("%d\n", ask(u)-1); }
        else throw;
    }
    return 0;
}

LCT(TLE)

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 250005;
int chl[MAXN][2], dat[MAXN], hv[MAXN], stk[MAXN], stktop = 0, fa[MAXN];
int rev[MAXN], n, m;

bool is_rt(int nd)
{ return nd != chl[fa[nd]][0] && nd != chl[fa[nd]][1]; }

void update(int nd)
{ dat[nd] = dat[chl[nd][0]] + dat[chl[nd][1]] + hv[nd];}

void pdw(int nd)
{
    if (!rev[nd]) return;
    int &lc = chl[nd][0], &rc = chl[nd][1]; rev[nd] = 0;
    if (lc) rev[lc] ^= 1;
    if (rc) rev[rc] ^= 1;
    swap(lc, rc);
}

void zig(int nd)
{
    int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
    int son = chl[nd][tp^1];
    if (!is_rt(p)) chl[g][tg] = nd; chl[nd][tp^1] = p, chl[p][tp] = son;
    fa[son] = p, fa[p] = nd, fa[nd] = g;
    update(p), update(nd);
}

void splay(int nd)
{
    stk[stktop = 1] = nd;
    for (int i = nd; !is_rt(i); i = fa[i]) stk[++stktop] = fa[i];
    while (stktop) pdw(stk[stktop--]);
    while (!is_rt(nd)) {
        int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
        if (is_rt(p)) { zig(nd); break; }
        else if (tp == tg) zig(p), zig(nd);
        else zig(nd), zig(nd);
    }
}

void access(int x)
{
    for (int y = 0; x; x = fa[y = x])
        splay(x), chl[x][1] = y, update(x);
}

void make_rt(int x)
{ access(x), splay(x), rev[x] ^= 1; }

void link(int i, int j)
{ make_rt(j), fa[j] = i, access(j); }

void change(int nd)
{ make_rt(nd), splay(nd), hv[nd]--, update(nd); }

int ask(int nd)
{ make_rt(1), access(nd), splay(nd); return hv[nd]+dat[chl[nd][0]]; }

int main()
{
    scanf("%d", &n);
    for (int i = 2; i <= n; i++) hv[i] = 1;
    for (int i = 1; i < n; i++) {
        int u, v; scanf("%d%d", &u, &v);
        if (u > v) swap(u, v);
        link(u, v);
    }
    scanf("%d", &m);
    for (int i = 1; i <= n+m-1; i++) {
        char c; int u, v;
        scanf("\n%c", &c);
        if (c == 'W') { scanf("%d", &u), printf("%d\n", ask(u)); }
        else if (c == 'A') { scanf("%d%d", &u, &v), change(max(u, v)); }
    }
    return 0;
}

dfn&BIT

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 250005;
int C[MAXN], n, dstop = 0;
int lowbit(int i) { return i&(-i); }
void modify(int pos, int dt)
{ for (int i = pos; i <= n; i += lowbit(i)) C[i] += dt; }
int sum(int pos)
{
    int ans = 0;
    for (int i = pos; i > 0; i -= lowbit(i)) { ans += C[i];}
    return ans;
}

struct node {
    int to, next;
} edge[MAXN];
int head[MAXN], top = 0;
void push(int i, int j)
{ ++top, edge[top] = (node){j, head[i]}, head[i] = top; }

int depth[MAXN], dfi[MAXN], dfo[MAXN], dft = 0;

void dfs(int nd)
{
    dfi[nd] = ++dft;
    for (int i = head[nd]; i; i = edge[i].next) {
        int to = edge[i].to;
        depth[to] = depth[nd]+1;
        dfs(to);
    }
    dfo[nd] = dft;
}

void change(int nd)
{ modify(dfi[nd], 1), modify(dfo[nd]+1, -1); }

int ask(int nd)
{ return depth[nd]-sum(dfi[nd]); }

int main()
{
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v; scanf("%d%d", &u, &v);
        if (u > v) swap(u,v);
        push(u, v);
    }
    depth[1] = 0, dfs(1);
    int m; scanf("%d", &m);
    for (int i = 1; i <= n+m-1; i++) {
        char s; int u, v;
        scanf("\n%c", &s);
        if (s == 'A') { scanf("%d%d", &u, &v), change(max(u,v)); }
        else if (s == 'W') {scanf("%d", &u), printf("%d\n", ask(u)); }
        else throw;
    }
    return 0;
}

4.13

bzoj3506: [Cqoi2014]排序机械臂

题面传送门

就是splay维护最小值和最小值位置,加上反转操作即可。
然而debug能力是硬伤…
注意重复元素的处理,就是 xixi(n+1)+i

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005;
int chl[MAXN][2], fa[MAXN], rev[MAXN], stk[MAXN], stktop = 0;
int top = 0, min_pos[MAXN], siz[MAXN], root = 0;
long long min_val[MAXN], dat[MAXN];

void update(int nd)
{
    min_val[nd] = min(dat[nd], min(min_val[chl[nd][0]], min_val[chl[nd][1]]));
    min_pos[nd] = min_val[nd] == min_val[chl[nd][0]] ? min_pos[chl[nd][0]] : (min_val[nd] == dat[nd] ? nd : min_pos[chl[nd][1]]);
    siz[nd] = siz[chl[nd][0]] + siz[chl[nd][1]] + 1;
}

inline int new_node(long long d) { return ++top, dat[top] = d, update(top), top;}

void pdw(int nd)
{
    if (!rev[nd]) return;
    int &lc = chl[nd][0], &rc = chl[nd][1];
    if (lc) rev[lc] ^= 1;
    if (rc) rev[rc] ^= 1;
    swap(lc, rc), rev[nd] ^= 1;
}

void zig(int nd)
{
    int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
    int son = chl[nd][tp^1];
    fa[son] = son==0?0:p, fa[p] = nd, fa[nd] = g;
    chl[g][tg] = g==0?0:nd, chl[nd][tp^1] = p, chl[p][tp] = son;
    root = g?root:nd;
    update(p), update(nd);
}

void splay(int nd, int tar = 0)
{
    stk[stktop = 1] = nd;
    for (int i = nd; fa[i]; i = fa[i]) stk[++stktop] = fa[i];
    for (; stktop; stktop--) pdw(stk[stktop]);
    while (fa[nd] != tar) {
        int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;
        if (g == tar) {zig(nd); break; }
        else if (tp == tg) zig(p), zig(nd);
        else zig(nd), zig(nd);
    }
}

void dfs(int nd)
{
    if (!nd) return;
    pdw(nd);
    dfs(chl[nd][0]);
    cerr << dat[nd] << " ";
    dfs(chl[nd][1]);
}

void insert(long long nd)
{
    if (root == 0) root = new_node(nd);
    else {
        chl[root][1] = new_node(nd), fa[top] = root;
        splay(top), update(top);
        // dfs(top);
    }
}

int get_min()
{
    splay(min_pos[root]);
    int ans = siz[chl[root][0]]+1;
    return ans;
}

int get_by_order(int k)
{
    int nd = root; k--; // have k element on left
    while (nd) {
        pdw(nd), update(nd);
        if (siz[chl[nd][0]] == k) break;
        nd = siz[chl[nd][0]]>k?chl[nd][0]:(k -= siz[chl[nd][0]]+1, chl[nd][1]);
    }
    return nd;
}

int get_segment(int l, int r)
{
    if (l == 1 && r == siz[root]) return root;
    if (l == 1) return splay(get_by_order(r+1)), chl[root][0];
    if (r == siz[root]) return splay(get_by_order(l-1)), chl[root][1];
    return splay(get_by_order(l-1)), splay(get_by_order(r+1), root), chl[chl[root][1]][0];
}

void del_root()
{
    int t = get_segment(siz[chl[root][0]]+1, siz[chl[root][0]]+1);
    int tp = chl[fa[t]][0] != t; chl[fa[t]][tp] = 0;
    for (int i = fa[t]; i; i = fa[i]) update(i);
    fa[t] = 0;
}

void reverse(int l, int r)
{
    int t = get_segment(l, r);
    rev[t] ^= 1;
}

int ans()
{
    int ret = get_min();
    reverse(1, ret);
    splay(min_pos[root]), del_root();
    return ret;
}

int n;

int main()
{
    memset(min_val, 127/3, sizeof min_val);
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int u; scanf("%d", &u); insert((long long)u*(n+1)+i);
    }
    for (int i = 1; i <= n; i++) printf("%d ", ans()+i-1);
    return 0;
}

bzoj3530: [Sdoi2014]数数

大爷题解:http://blog.csdn.net/aarongzk/article/details/50472209#

就是AC自动机上dp,然而数位dp仍然跪烂…要注意前导零的处理。
AC自动机忘记push儿子调试1h…

#include <bits/stdc++.h>
using namespace std;

const int MAXL = 1505;

int vis[MAXL];
struct ACM {
    struct node {
        int chl[10];
        int finished, fail;
        node() { memset(chl, 0, sizeof chl), finished = fail = 0; }
    } tree[MAXL];
    int top, root;
    ACM() { top = root = 0; }
    inline int new_node() { return ++top; }
    void insert(int &nd, const char *str)
    {
        if (!nd) nd = new_node();
        if (*str == '\0') tree[nd].finished = 1, vis[nd] = 1;
        else insert(tree[nd].chl[*str-'0'], str+1);
    }
    queue<int> que;
    void init()
    {
        tree[root].fail = 0, que.push(root);
        while (!que.empty()) {
            int nd = que.front(); que.pop(); vis[nd] |= vis[tree[nd].fail];
            for (int i = 0; i < 10; i++) {
                if (!tree[nd].chl[i]) continue;
                int p = tree[nd].fail;
                while (p && !tree[p].chl[i]) p = tree[p].fail;
                if (!p) tree[tree[nd].chl[i]].fail = root;
                else tree[tree[nd].chl[i]].fail = tree[p].chl[i];
                que.push(tree[nd].chl[i]);
            }
        } ;
    }
    int trans(int nd, int ths)
    {
        if (tree[nd].chl[ths]) return tree[nd].chl[ths];
        int p = tree[nd].fail;
        while (p && !tree[p].chl[ths]) p = tree[p].fail;
        if (!p) return root;
        else return tree[p].chl[ths];
    }
} ac;

long long dp[1500][MAXL][3]; // 1 随意 0 不随意
char str[MAXL]; int s[MAXL];
long long mod = 1e9+7;
int n, m;

int main()
{
    memset(vis, 0, sizeof vis);
    scanf("%s", str+1); n = strlen(str+1);
    for (int i = 1; i <= n; i++) s[i] = str[i]-'0';
    scanf("%d", &m);
    for (int i = 1; i <= m; i++) {
        scanf("%s", str);
        ac.insert(ac.root, str);
    }
    long long ans = 0;
    ac.init();
    memset(dp, 0, sizeof dp);
    for (int i = 1; i < 10; i++) if (!vis[ac.trans(ac.root, i)]) dp[2][ac.trans(ac.root, i)][0]++;
    for (int i = 2; i < n; i++)
        for (int j = 1; j <= ac.top; j++)
            for (int k = 0; k < 10; k++) if (!vis[ac.trans(j, k)])
                (dp[i+1][ac.trans(j, k)][0] += dp[i][j][0]) %= mod;
    for (int i = 2; i <= n; i++)
        for (int j = 1; j <= ac.top; j++)
            (ans += dp[i][j][0]) %= mod; // 前导0
    memset(dp, 0, sizeof dp);
    for (int i = 1; i <= s[1]; i++)
        if (!vis[ac.trans(ac.root, i)])
            dp[2][ac.trans(ac.root, i)][i == s[1]]++;
    for (int i = 2; i <= n; i++) {
        for (int j = 1; j <= ac.top; j++)
            for (int k = 0; k < 10; k++) {
                if (vis[ac.trans(j, k)]) continue;
                (dp[i+1][ac.trans(j, k)][0] += dp[i][j][0]) %= mod;
                if (k < s[i]) (dp[i+1][ac.trans(j, k)][0] += dp[i][j][1]) %= mod;
                else if (k == s[i]) (dp[i+1][ac.trans(j, k)][1] += dp[i][j][1]) %= mod;
            }
    }
    for (int i = 1; i <= ac.top; i++)
        (ans += dp[n+1][i][0]+dp[n+1][i][1]) %= mod;
    cout << ans << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物像数据,这些数据包括健康植物的像以及受不同病虫害影响的植物像。 2. **像预处理**:对收集到的像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值