Exchanging Gifts
[Link](Problem - E - Codeforces)
题意
给你n个操作,每个操作有两种类型,1. 1 m 接下来输入m个数表示这第i个序列是什么, 2. 2 a b 表示 第i个数列有第a个和第b个数列拼接而成。然后你可以对第n个序列进行操作,任意改变他的顺序,问操作后的数组最多有多少个位置的数与原数组相同位置的数不一样。
题解
因为可以随意改变顺序,所以发现当出现最多的数 m x mx mx的数量小于等于总数量 s u m / 2 sum/2 sum/2的时候,我们总可以使得所有的位置都和以前不一样,因此答案是 s u m sum sum,当 m x > s u m / 2 mx>sum/2 mx>sum/2的时候发现无论怎么换总有 m x ∗ 2 − s u m mx*2-sum mx∗2−sum的数还会在原来的位置,因此答案是 ( s u m − m x ) ∗ 2 (sum-mx)*2 (sum−mx)∗2。
但是发现这个序列最长可达 1 e 18 1e18 1e18,我们肯定没法把这个序列直接搞出来。因为每一个合成的序列都是由两个子序列构成的,所以我们可以想办法搞出来对第n个序列有贡献的不由其他序列构成的序列被用了多少次,这样再去统计这些序列里数出现的次数即可。假设第 i i i序列被用了 k k k次那么构成第 i i i个序列的子序列被用的次数也要加上 k k k,怎么去统计这个次数呢,对于构成第i个序列的子序列 u , v u,v u,v可以从 i 向 u , v i向u,v i向u,v各连一条边,我们可以先以n为根把和第n个序列有关的序列都搜出来并统计每个序列的入度,然后做一次拓扑排序,可以保证当前这个点入队的时候一定没有其他的点再去更新他了,所以可以统计出每个序列被用的次数。然后用有用的基序列的次数去推每个数出现的次数,统计一下sum和mx就可以啦。
因为这道题的读入太多了,所以不用快读的话会T。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e6 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
LL cnt[N];
int d[N], op[N];
vector<int> col[N];
unordered_map<int, LL> res;
queue<int> q;
bool st[N];
void init() {
while (q.size()) q.pop();
for (int i = 1; i <= n; i ++ ) {
h[i] = -1, d[i] = cnt[i] = op[i] = st[i] = 0;
col[i].clear();
}
res.clear(), idx = 0;
}
void bfs() {
q.push(n);
st[n] = true;
while (q.size()) {
LL t = q.front(); q.pop();
for (int i = h[t]; ~i; i = ne[i] ) {
int j = e[i];
d[j] ++;
if (!st[j]) q.push(j), st[j] = true;
}
}
}
void topsort() {
q.push(n);
while (q.size()) {
LL t = q.front(); q.pop();
for (int i = h[t]; ~i; i = ne[i] ) {
int j = e[i];
cnt[j] += cnt[t];
if (-- d[j] == 0) q.push(j);
}
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
read(T);
while (T -- ) {
read(n);
init();
for (int i = 1; i <= n; i ++ ) {
int a, b;
read(op[i]);
if (op[i] == 1) {
read(b);
for (int j = 0; j < b; j ++ ) read(a), col[i].push_back(a);
}
else {
read(a), read(b);
add(i, a), add(i, b);
}
}
cnt[n] = 1;
bfs(), topsort();
for (int i = 1; i <= n; i ++ )
if (cnt[i] && op[i] == 1)
for (auto x : col[i]) res[x] += cnt[i];
LL sum = 0, mx = 0;
for (auto x : res) {
sum += x.y;
if (x.y > mx) mx = x.y;
}
if (mx * 2 >= sum) cout << (sum - mx) * 2 << endl;
else cout << sum << endl;
}
return 0;
}