其他分享
首页 > 其他分享> > BUPT 2021 Winter Training #6

BUPT 2021 Winter Training #6

作者:互联网

C - Even Path

水题略

F - Regular Forestation

题意

给一棵树,求出一点使得删去这点后剩下的两棵以上的树两两同构,且剩下树的数量尽可能多

思路

只有重心可能为good cutting point,求出重心再进行检验即可。
(有两个重心时不存在good cutting point)

关于无根树同构

由于树可能有两个重心,而且重心可能不对称,因此判断无根树同构的时候要分别尝试两个重心。采用树哈希方法的时候要分别以两个重心为根算出有根树哈希值,再以某种方法合并。这里一开始在算以第二个重心为根的哈希的时候没有更新把size更新成以第二个重心为根。后来发现了不用size的哈希算法,简化了代码。

代码
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
struct Edge
{
    int v, next;
} e[8010];
int head[4010], cnt;
int sz[4010], tot;
int gcenter1, gcenter2, mn;
int ans;
void addedge(int u, int v)
{
    cnt++;
    e[cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}
void dfs(int u, int f)
{
    int mx = 0;
    sz[u] = 1;
    for (int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].v;
        if (v == f || v == ans) continue;
        dfs(v, u);
        sz[u] += sz[v];
        mx = max(mx, sz[v]);
    }
    mx = max(mx, tot - sz[u]);
    if (mx < mn)
    {
        gcenter1 = u;
        gcenter2 = 0;
        mn = mx;
    }
    else if (mx == mn)
    {
        gcenter2 = u;
    }
}
ull rooted_hash(int u, int f)
{
    vector<ull> sub_h;
    for (int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].v;
        if (v == f || v == ans) continue;
        sub_h.push_back(rooted_hash(v, u));
    }
    sort(sub_h.begin(), sub_h.end());
    ull h = 1;
    for (ull i : sub_h) h = (h * 7) ^ i;
    return h;
}
ull rootless_hash(int u, int totsz)
{
    mn = tot = totsz;
    dfs(u, 0);
    return rooted_hash(gcenter1, 0) + (gcenter2 ? rooted_hash(gcenter2, 0) : 0);
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i < n; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }
    int mxcnt = -1;
    mn = tot = n;
    dfs(1, 0);
    ans = gcenter1;
    dfs(ans, 0);
    int subsz = sz[e[head[ans]].v];
    ull h = rootless_hash(e[head[ans]].v, subsz);
    int count = 1;
    for (int i = e[head[ans]].next; i; i = e[i].next)
    {
        int v = e[i].v;
        count++;
        if (sz[v] != subsz || h != rootless_hash(v, sz[v]))
        {
            printf("-1\n");
            return 0;
        }
    }
    if (count == 1)
        printf("-1\n");
    else
        printf("%d\n", count);
    return 0;
}

K - Addition Robot

题意

给定一个由字符A或B构成的序列,进行两种操作:

  1. 反转指定区间内的字符
  2. 给定数值A、B以及一段区间,根据区间内的字符依次计算,遇到字符A则A+=B,遇到字符B则B+=A,输出最终A、B的值

思路

建立线段树,每个节点维护一个2x2矩阵,题目中的运算过程相当于矩阵乘向量,左右两端操作序列合并相当于右端对应矩阵乘左端对应矩阵,反转则相当于让矩阵旋转180°

代码
#include <bits/stdc++.h>
#define lc (u << 1)
#define rc (u << 1 | 1)
using namespace std;
typedef long long ll;
const int mod = 1000000007;
struct Mat
{
    ll a, b, c, d;
    Mat trans()
    {
        return (Mat){d, c, b, a};
    }
};
Mat operator*(Mat lhs, Mat rhs)
{
    return (Mat){(lhs.a * rhs.a + lhs.b * rhs.c) % mod, (lhs.a * rhs.b + lhs.b * rhs.d) % mod,
                 (lhs.c * rhs.a + lhs.d * rhs.c) % mod, (lhs.c * rhs.b + lhs.d * rhs.d) % mod};
}
Mat t[400010];
bool toggled[400010];
char a[100010];
void pushup(int u)
{
    t[u] = t[rc] * t[lc];
}
void pushdown(int u)
{
    if (toggled[u])
    {
        toggled[u] = false;
        toggled[lc] = !toggled[lc];
        toggled[rc] = !toggled[rc];
        t[lc] = t[lc].trans();
        t[rc] = t[rc].trans();
    }
}
void build(int u, int l, int r)
{
    if (l == r)
    {
        if (a[l] == 'A')
        {
            t[u] = (Mat){1, 1, 0, 1};
        }
        else
        {
            t[u] = (Mat){1, 0, 1, 1};
        }
        return;
    }
    int mid = (l + r) >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
    pushup(u);
}
Mat query(int u, int l, int r, int ql, int qr)
{
    if (ql <= l && qr >= r) return t[u];
    pushdown(u);
    int mid = (l + r) >> 1;
    Mat ans = {1, 0, 0, 1};
    if (qr >= mid + 1) ans = ans * query(rc, mid + 1, r, ql, qr);
    if (ql <= mid) ans = ans * query(lc, l, mid, ql, qr);
    return ans;
}
void toggle(int u, int l, int r, int ql, int qr)
{
    if (ql <= l && qr >= r)
    {
        toggled[u] = !toggled[u];
        t[u] = t[u].trans();
        return;
    }
    pushdown(u);
    int mid = (l + r) >> 1;
    if (ql <= mid) toggle(lc, l, mid, ql, qr);
    if (qr >= mid + 1) toggle(rc, mid + 1, r, ql, qr);
    pushup(u);
}
int main()
{
    int n, q;
    scanf("%d%d%s", &n, &q, a + 1);
    build(1, 1, n);
    while (q--)
    {
        int op, l, r, a, b;
        scanf("%d", &op);
        if (op == 1)
        {
            scanf("%d%d", &l, &r);
            toggle(1, 1, n, l, r);
        }
        else
        {
            scanf("%d%d%d%d", &l, &r, &a, &b);
            Mat mt = query(1, 1, n, l, r);
            ll na = (mt.a * a + mt.b * b) % mod;
            ll nb = (mt.c * a + mt.d * b) % mod;
            printf("%lld %lld\n", na, nb);
        }
    }
    return 0;
}

标签:sz,Training,int,BUPT,mid,2021,ans,head,mx
来源: https://www.cnblogs.com/teralem/p/15847449.html