A层邀请赛4

A. 暗之链锁

翻书就好了,在树上差分的第一个例题,书上讲得太好了感觉我写啥都是多余。Cat本来可以1A的,结果把m看成了树边和非树边总共有m条,算贡献的时候算成了n-m...过样例的的时候读入错了我就发现了这个问题,结果改了一处没改第二处……

有大佬说能用树链剖分+线段树,我懒了就没试,我的树链剖分是用来找lca的。

#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 1e5 + 2;
const ll mod = 1e9 + 7;

int n, m, top[maxn], fa[maxn], siz[maxn], dfn[maxn], rnk[maxn];
int c[maxn], dep[maxn], son[maxn], ntime;
ll ans;

struct node 
{
    int next, to;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y)
{
    a[++len].to = y; a[len].next = head[x];
    head[x] = len;
}

void find_heavy_edge(int u, int fat, int depth)
{
    fa[u] = fat;
    dep[u] = depth;
    siz[u] = 1;
    son[u] = 0;
    int maxsize = 0;
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(dep[v]) continue;
        find_heavy_edge(v, u, depth+1);
        siz[u] += siz[v];
        if(siz[v] > maxsize)
        {
            maxsize = siz[v];
            son[u] = v;
        }
    }
}

void connect_heavy_edge(int u, int ancestor)
{
    dfn[u] = ++ntime;
    top[u] = ancestor;
    rnk[ntime] = u;
    if(son[u])
    {
        connect_heavy_edge(son[u], ancestor);
    }
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == son[u] || v == fa[u]) continue;
        connect_heavy_edge(v, v);
    }
}

int LCA(int x, int y)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    return x;
}

void dfs(int u)
{
    for(int i=head[u]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == fa[u]) continue;
        dfs(v);
        c[u] += c[v];
    }
    if(u != 1)
    {
        if(c[u] == 0) ans += m;
        else if(c[u] == 1) ans++;
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i=1; i<n; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y); add(y, x);
    }
    find_heavy_edge(1, 1, 1);
    connect_heavy_edge(1, 1);
    for(int i=1; i<=m; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        c[x]++; c[y]++;
        int lca = LCA(x, y);
        c[lca] -= 2;
    }
    dfs(1);
    printf("%lld\n", ans);
  
    return 0;
}
View Code

 

B. 蚊子

(如果你算错了,就会被liu_runda拿去喂兔子,啊呜~~)

我不会算,兔子你吃了我吧,撑不死你……

所以,根据题解,杀死蚊子的概率不好求,应该求蚊子存活的概率,每只蚊子存活的概率都是(1-p/q)^k(k是路径上在d范围内的节点数),问题就变成了m*(m-1)-所有蚊子存活的概率之和,也就是求出树上任意两个叶子路径的权值乘积(深度>d权值为1,深度<=d权值为存活的概率)。

接下来的树上dp很显然吗我怎么不这么觉得……所以我无奈的去翻了一些其他大佬的题解……

最后对于乘法分配律什么的还是觉得有点感性理解……

//Cat 对 Chen_jr 的题解情有独钟
#include <bits/stdc++.h>
  
using namespace std;
  
typedef long long ll;
const int maxn = 5e6 + 5;
const int INF = 0x7fffffff;
const ll mod = 1e9 + 7;

int n, d;
ll qw, g[maxn], p, q, ans, m;

ll qpow(ll a, ll b)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

struct node 
{
    int next, to;
}a[maxn<<1];
int head[maxn], len;

void add(int x, int y)
{
    a[++len].to = y; a[len].next = head[x];
    head[x] = len;
}

char xch,xB[1<<15],*xS=xB,*xTT=xB;
#define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
inline int read(){
    int x=0,f=1;char ch=getc();
    while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}

void dfs(int x, int fa, int dep)
{
    //printf("x = %d\n", x);
    bool is = 1;
    for(int i=head[x]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == fa) continue;
        dfs(v, x, dep+1);
        is = 0;
        g[x] += g[v];
    }
    if(is) g[x] = 1, m++;
    else g[x] %= mod;
    ll now = dep <= d ? qw : 1;
    for(int i=head[x]; i; i=a[i].next)
    {
        int v = a[i].to;
        if(v == fa) continue;
        ans = (ans+g[v]*(g[x]-g[v]+mod)%mod*now)%mod;
    }
    g[x] = g[x]*now%mod;
}

int main()
{
    //freopen("ww.txt", "r", stdin);
    n = read();
    for(int i=1; i<n; i++)
    {
        int x = read(), y = read();
        add(x, y); add(y, x);
    }
    d = read(), p = read(), q = read();
    qw = (1-qpow(q, mod-2)*p%mod+mod)%mod;
    dfs(1, 1, 0);
    printf("%lld\n", ((m*(m-1)%mod-ans)%mod+mod)%mod);
    
    return 0;
}
View Code

 

posted @ 2022-08-15 21:53  Catherine_leah  阅读(26)  评论(0编辑  收藏  举报
/* */