题目链接
题目大意
有两种操作 第一种是列出一个序列 第二种是合并之前出现的序列生成一个新的序列
问你最后序列的快乐值是多少
快乐值定义是 将序列随意排序后最大的与之前位置不同的元素个数
题目思路
经过观察发现
最大快乐值
数量最多的元素数量=maxv
总元素数量=tot
当maxv<tot/2时 快乐值=tot
否则快乐值 =tot-(maxv-(tot-maxv))
列出如下之图可看得更明白
有上图到下图 明显不快乐值为 最大的数量5 -剩余数量4=1
快乐值=9-1=8
问题是如何找到各个元素数量
由于每个操作2可以吸收两个序列
可以很容易想到拓补
但是该题有一个条件就是2操作的对象序号小于 i
那么该题就不需要拓扑了 直接从n到1线性求解
设置num【n】=1
若该点是操作2则将操作对象的num+=num【i】
若该点是操作1则该点包含所有的点的数量+=num【i】
若某一个点num【i】==0 就跳过
这样的时间复杂度是O(N+K)
但由于读入数量级的问题 很容易T
因此我用了一个超级快读(注意该快读无法读入其他类型)
static char buf[100000],*pa=buf,*pd=buf;
#define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
register int x(0);register char c(gc);
while(c<'0'||c>'9')c=gc;
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;
return x;
}
题目代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int t,n,m,T,q,x,y;
int lef[maxn],inlj[maxn];
ll num[maxn];
ll tot,maxv;
unordered_map<int ,ll >mp;
static char buf[100000],*pa=buf,*pd=buf;
#define gc pa==pd&&(pd=(pa=buf)+fread(buf,1,100000,stdin),pa==pd)?EOF:*pa++
inline int read()
{
register int x(0);register char c(gc);
while(c<'0'||c>'9')c=gc;
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;
return x;
}
//void dfs(int floor)
//{
// if(lef[floor])
// for(int i=0;i<e[floor];i++)
// {
//
// }
//}
vector<int >v[maxn];
int main()
{
T=read();
while(T--)
{
n=read();
mp.clear();
tot=maxv=0;
for(int i=1;i<=n;i++)
{
t=read();
v[i].clear();
lef[i]=num[i]=0;
if(t==1)
{
q=read();
for(int j=0;j<q;j++)
{
x=read();
v[i].push_back(x);
}
}
else if(t==2)
{
x=read();
y=read();
v[i].push_back(x);
v[i].push_back(y);
lef[i]=1;
}
}
num[n]=1;
if(lef[n])
{
//dfs(n);
for(int i=n;i>=1;i--)
{
if(num[i]==0)continue;
int floor=i;
if(lef[floor]==1)
{
num[v[floor][0]]+=num[i];
num[v[floor][1]]+=num[i];
}
else
{
for(int j=0;j<v[floor].size();j++)
{
int y=v[floor][j];
mp[y]+=num[i];
maxv=max(maxv,mp[y]);
tot+=num[i];
}
}
}
}
else
{
int floor=1;
for(int j=0;j<v[floor].size();j++)
{
int y=v[floor][j];
mp[y]+=num[floor];
maxv=max(maxv,mp[y]);
tot+=num[floor];
}
}
if(maxv<=(tot)/2)
{
printf("%lld\n",tot);
}
else
{
ll tmp=maxv-(tot-maxv);
printf("%lld\n",tot-tmp);
}
}
return 0;
}