A层邀请赛4

A. 暗之链锁

树剖维护一下即可,其实树上差分也可

注意线段树空间开四倍!!!!!!!!!!

左移\(2\)

code
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
typedef long long ll;
inline int read(){
    int x = 0; char c = getchar();
    while(c < '0' || c > '9')c = getchar();
    do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
    return x;
}
const int maxn = 100005;
int head[maxn],tot,n,m;
struct edge{
    int to, net;
}e[maxn << 1 | 1];
void add(int u, int v){
    e[++tot].net = head[u];
    head[u] = tot;
    e[tot].to = v;
}
int id[maxn],dep[maxn],fa[maxn],son[maxn],top[maxn],size[maxn],nid[maxn];
int cnt[maxn];
struct tree{
    int t[maxn << 2 | 1];
    void push_down(int x){
        t[x << 1] += t[x];
        t[x << 1 | 1] += t[x];
        t[x] = 0;
    }
    void modify(int x,int l, int r, int L, int R){
        if(L <= l && r <= R){
            ++t[x];
            return;
        }
        if(t[x])push_down(x);
        int mid = ( l + r) >> 1;
        if(L <= mid)modify(x << 1, l, mid, L, R);
        if(R > mid)modify(x << 1 | 1, mid + 1, r, L , R);
    }
    void query(int x, int l, int r){
        if(l == r){
            cnt[nid[l]] = t[x];
            return;
        }
        if(t[x])push_down(x);
        int mid = (l + r) >> 1;
        query(x << 1, l ,mid);
        query(x << 1 | 1, mid + 1, r); 
    }
}T;
void dfs1(int x){
    size[x] = 1;
    for(int i = head[x]; i; i = e[i].net){
        int v = e[i].to;
        if(v == fa[x])continue;
        dep[v] = dep[x] + 1;
        fa[v] = x;
        dfs1(v);
        size[x] += size[v];
        if(size[v] > size[son[x]])son[x] = v;
    }
}
int tim;
void dfs2(int x, int tp){
    id[x] = ++tim; nid[tim] = x;
    top[x] = tp;
    if(son[x])dfs2(son[x],tp);
    for(int i = head[x]; i; i = e[i].net){
        int v = e[i].to;
        if(v == fa[x] || v == son[x])continue;
        dfs2(v, v);
    }
}
void work(){
    int u = read(), v = read();
    while(top[u] != top[v]){
        if(dep[top[u]] < dep[top[v]])swap(u, v);
        T.modify(1, 1, n, id[top[u]], id[u]);
        u = fa[top[u]];
    }
    if(u == v)return;
    if(dep[u] < dep[v])swap(u ,v);
    T.modify(1, 1, n, id[v] + 1, id[u]);
}
int main(){
    n = read(), m = read();
    for(int i = 1; i < n; ++i){
        int u = read(), v = read();
        add(u, v);add(v, u);
    }
    dep[1] = fa[1] = 1;dfs1(1);dfs2(1,1);
    for(int i = 1; i <= m; ++i)work();
    T.query(1, 1, n);
    ll ans = 0;
    for(int i = 2; i <= n; ++i){
        if(cnt[i] == 1)++ans;
        if(cnt[i] == 0)ans += m;
    }
    printf("%lld\n",ans);
    return 0;
}

B. 蚊子

这题告诉我优秀的题意转化是多么重要

杀死的概率不好求,但是存活的概率好求,用总数减去存活的期望就是杀死的期望

那么如何求存活的期望,发现问题可以转化为求树上任意两个叶子的路径的权值乘积,其中深度\(>=d\)的权值为1,小于等于\(d\)的权值为每次存活的概率

然后树\(DP\)就比较显然了,请读者自证

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
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;
}
const int maxn = 5000005;
const int mod = 1e9 + 7;
int head[maxn],tot,n;
struct edge{
    int to, net;
}e[maxn << 1 | 1];
void add(int u, int v){
    e[++tot].net = head[u];
    head[u] = tot;
    e[tot].to = v;
}
ll qpow(ll x, ll y){
    ll ans = 1;
    for(;y;y >>= 1, x = x * x % mod)if(y & 1)ans = ans * x % mod;
    return ans; 
}
int d;
ll qw, g[maxn], p, q, ans, m;
void dfs(int x, int fa, int dep){
    bool is = 1;
    for(register int i = head[x]; i; i = e[i].net){
        int v = e[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(register int i = head[x]; i; i = e[i].net){
        int v = e[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(){
    n = read();
    for(register int i = 1; i < n; ++i){
        int u = read(), v = read();
        add(u, v);add(v, u);
    }
    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;
}
posted @ 2022-07-29 07:16  Chen_jr  阅读(33)  评论(0编辑  收藏  举报