第6题
给定一棵n个节点的树,点权未知且各不相同。定义点 u 的 bu 为mex(sub(u))。其中mex(集合),值为其集合中最小的未出现的非负整数。sub(u)为子树中的点权的集合。求b的和的最大值。当某个叶子节点的权值为0时,从根节点到该叶节点的那一条链上的mex(u)最大可以为sub(u)的值,所以遍历整个树取最大值。
我们用了好久才看懂MEX,所以也就慢了一点,就是遍历整个树,寻找一条链上的mex(u)的最大值就可以了,不过为了减少循环量,可以直接用2次遍历,小小的优化。
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=5e5+10;
int h[2*N],e[2*N],ne[2*N],idx;
long long siz[N],siz1[N];
void add(int a,int b){
e[++idx]=b;
ne[idx]=h[a];
h[a]=idx;
}
void dfsz(int u,int fa){
siz[u]=1;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(j==fa) continue;
dfsz(j,u);
siz[u]+=siz[j];
}
}
void dfs(int u,int fa){
siz1[u]=siz[u]+siz1[fa];
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(j==fa) continue;
dfs(j,u);
}
}
void solve(){
memset(h,-1,sizeof h);
memset(e,0,sizeof e);
memset(ne,0,sizeof ne);
memset(siz,0,sizeof siz);
memset(siz1,0,sizeof siz1);
idx=0;
cin>>n;
for(int i=1;i<n;i++){
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
dfsz(1,0);
dfs(1,0);
long long ans=0;
for(int i=1;i<=n;i++){
if(siz1[i]>ans) ans=siz1[i];
}
cout<<ans<<endl;
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
solve();
}
}
第10题
我们说无向图是平面图,如果它存在一种在平面上绘制它的方法,使得除了端点之外没有两条边有交点。例如,下图是一个平面图:
但是下面的这张图不是平面图,因为可以证明,无论如何在平面上绘制此图,至少有两条边具有不是端点的交集:
对于平面图,它具有一些由边分隔的区域。例如,下面的平面图具有44区域(注意该区域11是外部的无限平面):
给你一个平面图nn顶点和mm边缘。每个地区设定一个国家。你是设计师,你想在边缘上建造一些隧道,这样:从一个城市出发,你可以通过一些隧道或经过一些城市(即,除非它设置隧道,否则你不能越过一个边缘)。例如,对于上图,您可以像这样构建隧道:
在上图中,您可以从城市出发22到城市33通过隧道11,经过城市11,然后通过隧道33,经过城市44,终于通过隧道22,你可以到达城市33.你可以检查从任何城市你可以旅行到任何其他城市。
您希望隧道的数量尽可能小。打印最小隧道数和在其上构建隧道的边的 ID。
这道题目我没有特别搞懂,是队友带飞AC的,比赛的时候我连题目都没看wwww。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
const int M=2e5+7;
int f[N];
struct node{
int st,en;
}edge[M];
int getf(int x){
if(f[x]==x)return x;
return f[x]=getf(f[x]);
}
void solve(){
bool is[M];
memset(is,0,sizeof(is));
int ans=0,num[M];
int n,m,u,v;
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>v;
edge[i].st=u;
edge[i].en=v;
}
ans=m;
int cnt=m;
for(int i=1;i<=n;i++)f[i]=i;
int k=1;
int fta,ftb;
for(int i=m;i>=1;i--){
fta=getf(edge[i].st);
ftb=getf(edge[i].en);
if(fta!=ftb){
f[fta]=ftb;
cnt--;
is[i]=1;
}
}
cout<<cnt<<endl;
for(int i=1;i<=m;i++){
if(is[i]==0)cout<<i<<' ';
}
cout<<endl;
}
int main(){
cin.tie(0);
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--)solve();
}
第12题
给定一个数组 a ,可以执行一个操作k次。操作为选择一个区间 [L,R],让区间整体左移一位,a[L]到a[R]的位置上。求a的最大字典序。
明显就是贪心。这个操作等价于选择一个数,然后把它放到后面的任意一个位置。但我们也是这种思路,不知道为什么一直在wa,最后也没写出来。
#include<bits/stdc++.h>
using namespace std;
int t,n,k,a[300005],num,ti;
struct op{
int x,p;
};
op b[300005];
bool flag;
bool cmp(int x,int y)
{
if (x>y)
return 1;
else
return 0;
}
bool cmpt(op x,op y)
{
if (x.x>y.x)
return 1;
else if (x.x==y.x && x.p<y.p)
return 1;
return 0;
}
int main()
{
scanf("%d",&t);
for (int i=1;i<=t;i++){
scanf("%d%d",&n,&k);
for (int j=1;j<=n;j++)
scanf("%d",&a[j]);
/* if (k>=n*n){
sort(a+1,a+1+n,cmp);
for (int j=1;j<=n;j++)
printf("%d",a[j]);
continue;
}*/
num=0;
while(k--){
for (int j=1;j<n;j++){
flag=true;
if (a[j]==-1)
continue;
int x=j+1;
while (a[x]==-1)
x++;
if (a[j]<a[x]){
num++;
b[num].x=a[j];
b[num].p=j;
a[j]=-1;
flag=false;
break;
}
}
if (flag)
break;
}
sort(b+1,b+num+1,cmpt);
// for (int j=1;j<=num;j++)
// cout<<b[j].x<<" ";
ti=0;
for (int j=1;j<=n;j++){
if (a[j]==-1)
continue;
for (int l=1;l<=num;l++)
{
if (b[l].x>a[j] && b[l].x!=-1 && b[l].p<j){
if (ti!=n-1)
{
cout<<b[l].x<<" ";
ti++;
// cout<<ti<<" ";
}
else
cout<<b[l].x;
b[l].x=-1;
}
}
if (ti!=n-1)
{
cout<<a[j]<<" ";
ti++;
// cout<<ti<<" ";
}
else
cout<<a[j];
}
for (int j=1;j<=num;j++)
if (ti!=n-1)
{
cout<<b[j].x<<" ";
ti++;
// cout<<ti<<" ";
}
else
cout<<b[j].x;
}
return 0;
}
但看其他大佬的代码,明显会更简洁清晰,所以能搞懂,但确实不知道自己哪错了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
const int Max = 0x3f3f3f3f;
int t, n, k;
int a[maxn];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> t;
while (t--)
{
cin >> n >> k;
vector<int> sta, res;
priority_queue<int> q;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
{
while (sta.size() && sta.back() < a[i] && k)
{
q.push(sta.back());
sta.pop_back();
k--;
}
sta.push_back(a[i]);
}
int id = 0;
sta.push_back(-Max);
q.push(-Max);
while (res.size() < n)
{
if (sta[id] >= q.top())
res.push_back(sta[id]), id++;
else
res.push_back(q.top()), q.pop();
}
cout << res[0];
for (int i = 1; i < res.size(); i++)
cout << " " << res[i];
cout << endl;
}
return 0;
}