[Codeforces 715C] Digit Tree

[题目链接]

https://codeforces.com/contest/715/problem/C

[算法]

考虑点分治

一条路径(x , y)合法当且仅当 : d(x) * 10 ^ dep(x) + d(y) = 0(mod m) , 其中d(u)表示u到分治重心路径上数字拼接起来所形成的数

统计答案时 , 我们只需维护一个map , 维护10 ^ -dep(u) * d(u) (mod m)

然后计算每个点的贡献即可

时间复杂度 : O(NlogN ^ 2)

[代码]

#include<bits/stdc++.h>
using namespace std;
#define N 100010
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;

struct edge
{
        int to , w , nxt;
} e[N << 1];

int n , m , tot , len , root;
ll ans;
int pw[N] , head[N] , size[N] , weight[N] , D[N] , depth[N];
bool visited[N];
map<int , int> mp;

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - ‘0‘;
    x *= f;
}
inline void addedge(int u , int v , int w)
{
        ++tot;
        e[tot] = (edge){v , w , head[u]};
        head[u] = tot;
}
inline void getroot(int u , int par , int total)
{
        size[u] = 1;
        weight[u] = 0;
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to;
                if (v == par || visited[v]) continue;
                getroot(v , u , total);
                size[u] += size[v];
                chkmax(weight[u] , size[v]);
        }
        chkmax(weight[u] , total - size[u]);
        if (weight[u] < weight[root]) root = u;
}
inline void exgcd(int a , int b , int &x , int &y)
{
        if (b == 0)
        {
                x = 1;
                y = 0;
        } else
        {
                exgcd(b , a % b , y , x);
                y -= a / b * x;
        }
}
inline int inv(int a)
{
        int x , y;
        exgcd(a , m , x , y);
        return (x % m + m) % m;
}
inline void dfs(int u , int par , int d1 , int d2)
{
        if (depth[u] > 0) ++mp[(1ll * d2 % m * inv(pw[depth[u]] % m)) % m];
        D[++len] = d1;
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to , w = e[i].w;
                if (v == par || visited[v]) continue;
                depth[v] = depth[u] + 1;
                dfs(v , u , (1ll * w * pw[depth[v] - 1] % m + d1) % m , (10ll * d2 % m + w) % m);
        }
}
inline ll calc(int u , int d)
{
        mp.clear();
        len = 0;
        if (!d) dfs(u , -1 , 0 , 0);
        else dfs(u , -1 , d % m , d % m);
        ll res = 0;
        for (int i = 1; i <= len; ++i)
        {
                int goal = ((m - D[i]) % m + m) % m;
                res += (ll)mp[goal];
                if (!d && !D[i]) ++res;
        }
        return res;
}
inline void work(int u)
{
        visited[u] = true;
        depth[u] = 0;
        ans += calc(u , 0);
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to , w = e[i].w;
                if (visited[v]) continue;
                depth[v] = 1;
                ans -= calc(v , w);
        }
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to;
                if (visited[v]) continue;
                root = 0;
                getroot(v , u , size[v]);
                work(root);
        }
}

int main()
{

        read(n); read(m);
        pw[0] = 1;
        for (int i = 1; i <= n; ++i) pw[i] = 1ll * pw[i - 1] * 10 % m;
        for (int i = 1; i < n; ++i)
        {
                int u , v , w;
                read(u); read(v); read(w);
                ++u; ++v;
                addedge(u , v , w);
                addedge(v , u , w);
        }
        weight[0] = n;
        root = 0;
        getroot(1 , 0 , n);
        work(root);
        ans -= n;
        printf("%I64d\n" , ans);

        return 0;

}

原文地址:https://www.cnblogs.com/evenbao/p/10544912.html

时间: 2024-08-01 12:49:36

[Codeforces 715C] Digit Tree的相关文章

【题解】Digit Tree

[题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. 很明显可以点分治嘛,我们可以按照图上的样子,把一条路径本来是\(12345678\)的路径,变成\(1234|5678\),我们记录图中左边的那种路径为\(f\)(往根),右边的那种路径为\(g\)(从根),记右边的那种到分治中心的深度为\(d\),那么这条路径就可以被表示成\(f\times 1

Problem - D - Codeforces Fix a Tree

Problem - D - Codeforces  Fix a Tree 看完第一名的代码,顿然醒悟... 我可以把所有单独的点全部当成线,那么只有线和环. 如果全是线的话,直接线的条数-1,便是操作数. 如果有环和线,环被打开的同时,接入到线上.那就是线和环的总数-1. 如果只有环的话,把所有的环打开,互相接入,共需n次操作. #include <cstdio> #include <algorithm> using namespace std; const int maxn =

CodeForces - 383C Propagating tree(dfs + 线段树)

题目大意: 给出一棵树,树上每个节点都有权值,然后有两个操作. 1 x val 在结点x上加上一个值val,x的儿子加上 -val,x的儿子的儿子加上 - (-val),以此类推. 2 x 问x节点的值. 思路分析: 每个节点上加值都是给自己的儿子节点加,而且这个是颗树. 比如样例上的,如果你给node 1加一个值,那么五个节点都加. 再给node 2加个值,2的儿子节点也加了,之前给1加的值也要加到2号节点的儿子. 所以你会发现节点的儿子会存在一个从属的关系. 这样的话,我们可以把所有节点从新

CodeForces 383C Propagating tree

Propagating tree Time Limit: 2000ms Memory Limit: 262144KB This problem will be judged on CodeForces. Original ID: 383C64-bit integer IO format: %I64d      Java class name: (Any) Iahub likes trees very much. Recently he discovered an interesting tree

codeforces 570 D. Tree Requests 树状数组+dfs搜索序

链接:http://codeforces.com/problemset/problem/570/D D. Tree Requests time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Roman planted a tree consisting of n vertices. Each vertex contains a low

Codeforces 343D Water Tree(DFS序+线段树+技巧)

题目链接:http://codeforces.com/problemset/problem/343/D 题目: Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a reservoir which can be either empty or filled with water. The vertices of the tree are numbered f

CodeForces 593D Happy Tree Party

题目链接: http://codeforces.com/problemset/problem/593/D --------------------------------------------------------------------------------------------------------------- 刚看完题目感觉必须用树链剖分之类的方法,就放弃了,然而我们要发现题目具有如下性质: 一个$ long long $以内的数如果被大于$1$的数除 几十次就可以除到$0$了

Codeforces 196C Paint Tree(贪心+极角排序)

题目链接 Paint Tree 给你一棵n个点的树和n个直角坐标系上的点,现在要把树上的n个点映射到直角坐标系的n个点中,要求是除了在顶点处不能有线段的相交. 我们先选一个在直角坐标系中的最左下角的点,把根结点放到这个点中,然后对剩下的点进行极角排序,按逆时顺序一个个塞进来,类似地递归处理. 这样就满足了题意. #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b

codeforces 570 D Tree Requests

题意:给出一棵树.每一个结点都有一个字母,有非常多次询问,每次询问.以结点v为根的子树中高度为h的后代是否可以经过调整变成一个回文串. 做法: 推断能否够构成一个回文串的话,仅仅须要知道是否有大于一个的奇数数目的字母就可以.为了非常快的訪问到一个区间.记录前缀和就可以.为了省内存,状压奇偶就可以. 为了非常快的找到以结点v为根的子树中高度为h的后代,须要dfs整棵树.然后记录每一个结点第一次訪问它的时间戳以及离开它的时间戳,就能够二分出来. 为了省内存,能够离线处理询问. #include<ma