2022杭电多校6
1006 F Maex
题意:
给定一颗树,树上的每个节点有一个权值,权值互不相等。定义mex(i)为以 i 为根的子树上最小的没出现的正整数。对每一个节点的权值进行构造
,求整颗树的所有节点的mex的最大值。
分析:
void dfs(int u, int fa) {
siz[u] = 1;
int mx = 0;
for (int v : g[u]) {
if (v == fa)continue;
dfs(v, u);
siz[u] += siz[v];
mx = max(mx, dp[v]);
}
dp[u] = mx + siz[u];
}
void slove() {
cin >> n;
for (int i = 1; i <= n; i++)g[i].clear(), siz[i] = 0, dp[i] = 0;
for (int i = 1; i <= n - 1; i++) {
int u, v; cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
cout << dp[1] << endl;
}
1010 J Planar graph
题意:
给定一个平面图,图中有许多边把图分成了许多部分。我们能够在每个分割图的边上建立一个地下通道穿梭到另一个图。我们需要让图中每一块图都能够互相
到达,请问求出建立通道的最少数量以及字典序最小的建立通道的方式。
分析:
我们建桥的操作,可以看成删除边。
最后面可以相互联通,就是要求我们删边后,使得图没有环。
没有环就是需要是树(或者是森林)。那么这个就是个一个最小生成树(边权为1)。
要求字典序最小,我们直接倒着枚举边,这样可以使得编号大的边被保留,编号小的被删除(记录到方案中)。
#include <iostream>
#include <vector>
using namespace std;
const int N = 300010;
int n, m, p[N];
pair<int, int> e[N];
int find(int x)
{
return x == p[x] ? x : p[x] = find(p[x]);
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) p[i] = i;
for (int i = 1; i <= m; i ++)
cin >> e[i].first >> e[i].second;
vector<int> v;
for (int i = m; i; i--)
{
int a = e[i].first, b = e[i].second;
a = find(a), b = find(b);
if (a == b) v.push_back(i);
else p[a] = b;
}
cout << v.size() << '\n';
for (int i = v.size() - 1; ~i; i--) cout << v[i] << ' ';
cout << '\n';
}
int main() {
cin.tie(0)->sync_with_stdio(false);
int T;
cin >> T;
while (T--) solve();
return 0;
}
1007.Shinobu loves trip
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
typedef pair<int,int>PII;
const int N=2e5+10,INF=0x3f3f3f3f;
int n,m,a,P,ans;
int s[N],d[N];
int incf[N],x;
int qmi(LL a,LL k,LL p){
int res=1;
while(k){
if(k&1)res=res*a%p;
k>>=1;
a=a*a%p;
}
return res;
}
vold solve(){
cin>>P>>a>>n>>m;
map<int,int>mp;
int mark=1,t=0;
while(t<N){
if(!mp.count(mark)){
mp[mark]=t;
mark=mark*a%P;
t++;
}
}
for(int i=1;i<=n;i++){
cin>>s[i]>>d[i];
if(s[i]!=0)incf[i]=qmi(s[i],P-2);
}
while(m--){
cin>>x;
ans=0;
if(x==0){
for(int i=1;i<=n;i++)if(s[i]==0)ans++;
}else{
for(int i=1;i<=n;i++){
if(s[i]){
int temp=x*incf[i]%P;
if(mp.count(temp) && mp[t]<=d[i])ans++;
}
}
}
cout<<ans<<endl;
}
}
signed main(){
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
1012 L Loop
题意:
给定一个长度为n的数组,你可以进行k次操作,每次操作可以把一个数拿出来,后面的数整体前移,然后选择一个点插入该数。请问必须进行k次操作的前提
下,能够使数组的字典序最大。
分析:
因为要求字典序最大 贪心 从前往后开始处理
因为只能进行k次操作 所以想到要处理前面k个相对较小的 但是并不一定是前k个!!!
比如
当k=2 时 2 3 6 5 4 就应该取得2 3
当k=2 时 2 5 3 6 5 2 就应该取得2 3
那到底应该怎么判断呢?
用单调栈即可 !!!!
后面就贪心就好
void slove() {
cin >> n >> k;
for (int i = 1; i <= n; i++)cin >> a[i];
vector<int>stk;
priority_queue<int>del;
for (int i = 1; i <= n; i++) {
while (stk.size() && stk.back() < a[i] && k) {
del.push(stk.back());
stk.pop_back(), k--;
}
stk.push_back(a[i]);
}
vector<int>ans;
int id = 0;
stk.push_back(-INF), del.push(-INF);
while (ans.size() < n) {
if (stk[id] >= del.top())ans.push_back(stk[id++]);
else ans.push_back(del.top()), del.pop();
}
for (int i = 0; i < ans.size(); i++) {
if (i)cout << " ";;
cout << ans[i];
}
cout << endl;
}