来自学长的馈赠6

A. ^_^

考虑一个节点有贡献,当且仅当它比子树内所有点先被选中,那么显然答案就是

\(\sum1/size[x]\)

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

using namespace std;
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;
}
typedef long long ll;
const int maxn = 10000005;
const ll mod = 998244353;
ll qpow(ll x, int y){
    ll ans = 1;
    for(;y;y>>=1,x =x * x % mod)if(y & 1)ans = ans * x % mod;
    return ans;
}
int size[maxn], fa[maxn];
ll inv[maxn];
int main(){
	int n = read();
	for(int i = 2; i <= n; ++i)fa[i] = read();
	for(int i = n; i >= 1; --i){
		++size[i];
		size[fa[i]] += size[i];
	}
	for(ll i = 1; i <= n; ++i)inv[i] = qpow(i, mod - 2);
	ll ans = 0;
	for(int i = 1; i <= n; ++i){
		ans = (ans + inv[size[i]]) % mod;
	}
	printf("%lld\n",ans);
    return 0;
}

B. 软件包管理器

树剖板子

树剖维护的\(dfs\)序能够处理子树内问题!!!!!

code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
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;
}
typedef long long ll;
const int maxn = 100005;
int n, fa[maxn], q, tot, head[maxn];
char c[15];
int son[maxn], top[maxn], dep[maxn], size[maxn], id[maxn];
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;
}
void dfs1(int x){
	size[x] = 1;
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		fa[v] = x; dep[v] = dep[x] + 1;
		dfs1(v);
		size[x] += size[v];
		if(size[son[x]] < size[v])son[x] = v;
	}
}
int tim;
void dfs2(int x, int tp){
	top[x] = tp; id[x] = ++tim;
	if(son[x])dfs2(son[x], tp);
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(v == son[x])continue;
		dfs2(v, v);
	}
}
struct tree{
	struct node{
		int size,tag;
	}t[maxn << 2 | 1];
	void push_up(int x){t[x].size = t[x << 1].size + t[x << 1 | 1].size;}
	void push_down(int x, int l, int r){
		int ls = x << 1,rs = x << 1 | 1, mid = (l + r) >> 1;
		t[ls].tag = t[rs].tag = t[x].tag;
		t[ls].size = t[rs].size = 0;
		if(t[x].tag == 1){
			t[ls].size = mid - l + 1;
			t[rs].size = r - mid;
		}
		t[x].tag = 0;
	}
	void modify(int x, int l, int r, int L, int R, int dt){
		if(L <= l && r <= R){
			t[x].size = dt * (r - l + 1);
			t[x].tag = dt ? 1 : -1;
			return;
		}
		if(t[x].tag)push_down(x, l, r);
		int mid = (l + r) >> 1;
		if(L <= mid)modify(x << 1, l, mid, L, R, dt);
		if(R > mid)modify(x << 1 | 1, mid + 1, r, L, R, dt);
		push_up(x);
	}
	int query(int x, int l, int r, int L, int R){
		if(L <= l && r <= R)return t[x].size;
		if(t[x].tag)push_down(x, l, r);
		int mid = (l + r) >> 1, ans = 0;
		if(L <= mid)ans += query(x << 1, l, mid, L, R);
		if(R > mid)ans += query(x << 1 | 1, mid + 1, r, L, R);
		return ans;
	}
}t;
void install(int x){
	int u = x, cnt = 0;
	while(u){
		cnt += t.query(1, 1, n, id[top[u]], id[u]);
		t.modify(1, 1, n, id[top[u]], id[u], 1);
		u = fa[top[u]];
	}
	cnt = dep[x] - cnt;
	printf("%d\n",cnt);
}
void uninstall(int x){
	int cnt = t.query(1, 1, n, id[x], id[x] + size[x] - 1);
	t.modify(1, 1, n, id[x], id[x] + size[x] - 1, 0);
	printf("%d\n",cnt);
}
int main(){
	n = read();
	for(int i = 2; i <= n; ++i){
		fa[i] = read() + 1;
		add(fa[i], i);
	}
	dep[1] = 1; fa[1] = 0;
	dfs1(1); dfs2(1,1);
	q = read();
	for(int i = 1; i <= q; ++i){
		scanf("%s",c);
		int x = read() + 1;
		if(c[0] == 'i')install(x);
		else uninstall(x);
	}
	return 0;
}

C. 地理课

对每条边找出其作用的区间,然后在线段树上修改对应区间

进行一次线段树\(DFS\),配合可以撤销的并查集,按秩合并

code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
#include <queue>
#include <vector>
using namespace std;
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;
}
typedef long long ll;
const int maxn = 200005;
const int mod = 1e9 + 7;
int qpow(int x, int y) {
    int ans = 1;
    for (; y; y >>= 1, x = 1ll * x * x % mod)
        if (y & 1) ans = 1ll * ans * x % mod;
    return ans;
}
int n, m, top;
ll inv[maxn];
struct stac{
    int s, f1, f2, id;
}rem[maxn << 3 | 1];
struct SET{
    int f[maxn], size[maxn];
    void pre() {
        for (int i = 1; i <= n; ++i) f[i] = i;
        for (int i = 1; i <= n; ++i) size[i] = 1;
    }
    int fa(int x) {
        return f[x] == x ? x : fa(f[x]);
    }
} s;
struct op {
    int op, x, y, r;
} o[maxn];
int ans[maxn];
struct Tree{
    vector<int> v[maxn << 2 | 1];
    void modify(int x, int l, int r, int L, int R, int now) {
        if (L <= l && r <= R) {
            v[x].push_back(now);
            return;
        }
        int mid = (l + r) >> 1;
        if (L <= mid) modify(x << 1, l, mid, L, R, now);
        if (R > mid) modify(x << 1 | 1, mid + 1, r, L, R, now);
    }
    ll nans = 1;
    void LINK(int x) {
        for (int i : v[x]) {
            int u = o[i].x, v = o[i].y;
            u = s.fa(u);
            v = s.fa(v);
            if (u == v) continue;
            if (s.size[u] < s.size[v]) swap(u, v);
			nans = nans * inv[s.size[u]] % mod * inv[s.size[v]] % mod;
			rem[++top].f1 = v;
            rem[top].f2 = u;
            rem[top].s = s.size[v];
            rem[top].id = x;
            s.size[u] += s.size[v];
			s.size[v] = 0;
			nans = nans * s.size[u] % mod;
            s.f[v] = u;
        }
    }
    void CUT(int x) {
		while(rem[top].id == x){
			stac &o = rem[top];
			if(o.id != x)return;
			s.f[o.f1] = o.f1;
			s.f[o.f2] = o.f2;
			nans = nans * inv[s.size[o.f2]] % mod;
			s.size[o.f2] -= o.s;
			s.size[o.f1] = o.s;
			nans = nans * s.size[o.f1] % mod * s.size[o.f2] % mod;
			--top;
		}
    }
    void work(int x, int l, int r) {
		// printf("%d %lld\n",x,nans);
        LINK(x);
        if (l == r) {
			ans[l] = nans;
            CUT(x);
            return;
        }
        int mid = (l + r) >> 1;
        work(x << 1, l, mid);
        work(x << 1 | 1, mid + 1, r);
        CUT(x);
    }
} t;
typedef pair<int, int> pii;
map<pii, int> mp;
int main() {
    n = read(), m = read();
    inv[1] = 1;
    for (int i = 2; i <= n; i++)
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	s.pre();
    for (int i = 1; i <= m; ++i) {
        o[i].op = read();
        o[i].x = read();
        o[i].y = read();
        if (o[i].x > o[i].y) swap(o[i].x, o[i].y);
        if (o[i].op == 2) {
            o[mp[pii(o[i].x, o[i].y)]].r = i - 1;
        }else mp[pii(o[i].x, o[i].y)] = i;
	}
    for (int i = 1; i <= m; ++i)
	{
        if (o[i].op == 1) t.modify(1, 1, m, i, o[i].r ? o[i].r : m, i);
	}
	t.work(1, 1, m);
	for (int i = 1; i <= m; ++i)printf("%d\n",ans[i]);
    return 0;
}

D. 道路和航线

考场写出数据生成器,完美展现了题解思路

然而就是没写出正解,乱改\(dij\)还把\(spfa\)\(30\)分改没了

正解就是对不同联通块整体拓扑,每次把一个块内点全部入队

rand
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
mt19937 rd((ull)(new char) * (ull) (new char));
int sr(int l, int r){
    uniform_int_distribution<>d(l, r);
    return d(rd);
}
int bl[25005];
int lim = 10;
int main(){
    int t = 5, r = 3, p = 3;
    int s = sr(1, t);
    int fk = 20;
    for(int i = 1; i <= t; ++i){
        bl[i] = sr(1,fk);//(i % fk) + 1;
    }
    printf("%d %d %d %d\n",t,r,p,s);
    for(int i = 1; i <= r; ++i){
        int u = sr(1, t), v = sr(1, t);
        while(bl[u]!=bl[v]){
            u = sr(1, t), v = sr(1, t);
        }
        printf("%d %d %d\n",u,v,sr(0,lim));
    }
    for(int i = 1; i <= p; ++i){
        int u = sr(1, t);
        int v = sr(1, t);
        while(bl[u] >= bl[v]){
            u = sr(1, t);
            v = sr(1,t);
        }
        printf("%d %d %d\n",u,v,sr(-lim,lim));
    }
    return 0;
}
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
inline int read(){
    int x = 0; bool f = 0; char c = getchar();
    while(c < '0' || c > '9'){if(c == '-')f = 1;c = getchar();}
    do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
    return f ? -x: x;
}
typedef long long ll;
typedef pair<ll, int> pli;
const int maxn = 250055;
struct edge{
    int net,to,val;
}e[maxn << 1 | 1];
int head[maxn], tot;
ll dis[maxn];
void add(int u, int v, int val){
    e[++tot].net = head[u];
    head[u] = tot;
    e[tot].to = v;
    e[tot].val = val;
}
int t,r,p,s;
bool vis[maxn];
int belong[maxn], tim, rd[maxn];
vector<int> node[maxn];
void dfs(int x){
	belong[x] = tim;
	node[tim].push_back(x);
	for(int i = head[x]; i; i = e[i].net){
		int v = e[i].to;
		if(belong[v])continue;
		dfs(v);
	}
}
priority_queue<pli, vector<pli>, greater<pli> >q;
int main(){
    t = read(), r = read(), p = read(), s = read();
    for(int i = 1; i <= r; ++i){
        int a, b, c; a = read(), b = read(), c = read();
        add(a, b, c);add(b, a, c);
	}
	for(int i = 1; i <= t; ++i)if(!belong[i])++tim, dfs(i);
    for(int i = 1; i <= p; ++i){
        int a, b, c; a = read(), b = read(), c = read();
        add(a, b, c); ++rd[belong[b]];
    }
    memset(dis,0x3f,sizeof(dis)); 
	dis[s] = 0;
	for(int i = 1; i <= tim; ++i)
	  if(rd[i] <= 0) for(int j : node[i])q.push(make_pair(dis[j],j));
    while(!q.empty()){
        int x = q.top().second; q.pop();
        if(vis[x])continue;
        vis[x] = 1;
        for(int i = head[x]; i; i = e[i].net){
            int v = e[i].to;
			if(belong[v] != belong[x]){
				--rd[belong[v]];
				if(rd[belong[v]] <= 0) for(int y : node[belong[v]])q.push(make_pair(dis[y], y));
			}
			if(dis[x] == dis[maxn - 1])continue;	
			if(dis[v] > dis[x] + e[i].val){
                dis[v] = dis[x] + e[i].val;
                if(rd[belong[v]] <= 0){
					q.push(make_pair(dis[v], v));
				}
            }
			
        }
    }
    for(int i = 1; i <= t; ++i)
      if(dis[i] == dis[maxn - 1])printf("NO PATH\n");
      else printf("%lld\n",dis[i]);
    return 0;
}
posted @ 2022-07-31 11:46  Chen_jr  阅读(39)  评论(0编辑  收藏  举报