2020 wannafly camp day5 B Bitset Master —— 思維

題目鏈接:點我啊╭(╯^╰)╮

題目大意:

     nn 個點,n1n-1 條邊,mm 次操作
    每個點有一個集合,setset 裏最初只有自己
    每次操作將第 pip_i 條邊的兩個點的 setset 合併
    合併後兩個點的 setset 爲合併後的 setset
    最後問每個點被幾個 setset 包含

解題思路:

    f[u]f[v]f[u]、f[v] 表示 uuvvsetset 大小,合併後:
    f[u]=f[v]=f[u]+f[v]f[u]f[v]f[u] = f[v] = f[u] + f[v] - f[u] \bigcap f[v]
    f[u]f[v]f[u] \bigcap f[v] 表示兩個集合交,也就是上次合併的大小


    問題來了,怎麼求每個點去過幾個 setset 呢???
    題解說倒過來求就是了

    我的理解是倒過來的意義在於每次操作都是對後綴處理
    f[u]f[v]f[u]、f[v] 表示 uuvv 的能去多少個 setset,合併後:
    f[u]=f[v]=f[u]+f[v]f[u]f[v]f[u] = f[v] = f[u] + f[v] - f[u] \bigcap f[v]
    f[u]f[v]f[u] \bigcap f[v] 表示兩個點都能去的 setset 個數

    因爲是倒過來求
    f[u]+f[v]f[u]f[v]f[u] + f[v] - f[u] \bigcap f[v] 表示的就是完成後綴操作後
    兩者能去的 setset 個數

    我還能說什麼

核心:正難則反

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const int maxn = 5e5 + 5;
int n, m, p[maxn], f[maxn];
int gu[maxn], gv[maxn], g[maxn];

int main() {
	scanf("%d%d", &n, &m);
	for(int i=1; i<n; i++) scanf("%d%d", gu+i, gv+i);
	for(int i=1; i<=m; i++) scanf("%d", p+i);
	for(int i=1; i<=n; i++) f[i] = 1;
	for(int i=m, u, v; i; i--){
		u = gu[p[i]], v = gv[p[i]];
		f[u] = f[v] = f[u] + f[v] - g[p[i]];
		g[p[i]] = f[u];
	}
	for(int i=1; i<=n; i++) printf("%d%c", f[i], "\n "[i<n]);
}
發佈了231 篇原創文章 · 獲贊 226 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章