恩偶挨批模拟试题-17
作者:互联网
水博客太快乐了
考场
挂了。
分数
也挂了。
题解
A. 世界线
观察这题的本质,实际上就是每个点向所有它可以到达的点连一条边,但是已经有 \(m\) 条边了,所以答案减掉即可,不难想到联通数一题,考虑用 \(bitset\) 记下每个点可到达的点,相当于记忆化搜索。
但是这题卡空间, \(bitset\) 只能开一半,所以先统计一下能到达的小于等于 \(\frac{n}{2}\) 的点的个数,再统计一下能到达的大于 \(\frac{n}{2}\) 的个数,加一起即可。
code
#include<bits/stdc++.h>
using namespace std;
const int N=6e4+10;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int n, m;
int ans, ul;
bitset<(N>>1)> d[N];
vector<int> l[N];
bool vis[N];
void dfs(int u, bool op){
if(vis[u]) return;
vis[u]=1;
for(int v : l[u]){
if(!vis[v]) dfs(v, op); d[u]|=d[v];
if(!op&&v<=ul) d[u][v]=1;
if(op&&v>ul) d[u][v-ul]=1;
}
ans+=d[u].count();
}
int main(void){
n=read(), m=read(); int x, y;
for(int i=1; i<=m; ++i){
x=read(), y=read();
l[x].push_back(y);
}
ul=n>>1; ans-=m;
for(int i=1; i<=n; ++i) if(!vis[i]) dfs(i, 0);
for(int i=1; i<=n; ++i) d[i]&=d[0];
memset(vis, 0, sizeof vis);
for(int i=1; i<=n; ++i) if(!vis[i]) dfs(i, 1);
printf("%d\n", ans);
return 0;
}
B. 时间机器
考虑先按 \(l\) 排序,然后贪心,对于 \(l\) 所有小于当前节点的电池,优先使用 \(r\) 最接近这个节点的电池。用某种数据结构维护,可以用 \(set\) 或权值线段树。
为什么是正确的?显然是正确的。。。
code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e4+10;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int T, n, m;
struct node{
int l, r, num;
friend bool operator < (const node &x, const node &y) { return x.l < y.l; }
}a[N], b[N];
struct ul{
int r;
mutable int num;
ul(int r=0, int num=0):r(r),num(num){}
friend bool operator < (const ul &x, const ul&y) { return x.r!=y.r ? x.r<y.r : x.num<y.num; }
};
multiset<ul> s;
void solve(){
s.clear();
n=read(), m=read();
for(int i=1; i<=n; ++i) a[i]=(node){read(), read(), read() };
for(int i=1; i<=m; ++i) b[i]=(node){read(), read(), read() };
sort(a+1, a+1+n); sort(b+1, b+1+m);
for(int i=1, j=1; i<=n; ++i){
for(; j<=m&&b[j].l<=a[i].l; ++j) s.insert(ul(b[j].r, b[j].num));
while(a[i].num){
auto it=s.lower_bound(ul(a[i].r, 0));
if(it==s.end()) { puts("No"); return; }
if(it->num>a[i].num) { it->num-=a[i].num; break; }
a[i].num-=it->num; s.erase(it);
}
}
puts("Yes");
}
signed main(void){
T=read();
while(T--) solve();
return 0;
}
C. weight
裸的 \(MST\) 加树剖线段树。。
code
#include<bits/stdc++.h>
using namespace std;
#define t first
#define w second
const int N=7e4+10, M=1e5+10, INF=0x7fffffff;
inline int read(){
int f=1, x=0; char ch=getchar();
while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
return f*x;
}
int n, m, a;
int fa[N], top[N], dep[N], siz[N], val[N], son[N], num[N], num1[N], ind;
vector<pair<int, int> > l1[N];
struct TRE{
int l, r;
int minn, maxn;
}t[N<<2];
struct EDGE{
int f, t, w, id, ans;
bool ul;
friend bool operator < (const EDGE &x, const EDGE &y) { return x.w < y.w; }
}l[M];
bool cmp(const EDGE &x, const EDGE &y) { return x.id < y.id; }
void built(int l, int r, int p){
t[p].l=l, t[p].r=r, t[p].minn=INF;
if(l==r) { t[p].maxn=val[num1[l]]; return; }
int mid=(l+r)>>1;
built(l, mid, p<<1); built(mid+1, r, p<<1|1);
t[p].maxn=max(t[p<<1].maxn, t[p<<1|1].maxn);
}
void change(int l, int r, int x, int p){
if(l>r) return;
if(l<=t[p].l&&r>=t[p].r) { t[p].minn=min(t[p].minn, x); return; }
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) change(l, r, x, p<<1);
if(r>mid) change(l, r, x, p<<1|1);
}
int query(int l, int r, int p){
if(l>r) return 0;
if(l<=t[p].l&&r>=t[p].r) return t[p].maxn;
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid&&r>mid) return max(query(l, r, p<<1), query(l, r, p<<1|1));
if(l<=mid) return query(l, r, p<<1);
return query(l, r, p<<1|1);
}
void dfs3(int minn, int p){
minn=min(minn, t[p].minn);
if(t[p].l==t[p].r) { val[num1[t[p].l]]=minn; return; }
dfs3(minn, p<<1); dfs3(minn, p<<1|1);
}
void dfs1(int u, int f){
fa[u]=f; dep[u]=dep[f]+1; siz[u]=1;
for(pair<int, int > v : l1[u]){
if(v.t==f) continue; val[v.t]=v.w;
dfs1(v.t, u); siz[u]+=siz[v.t];
if(siz[v.t]>siz[son[u]]) son[u]=v.t;
}
}
void dfs2(int u, int tp){
top[u]=tp; num[u]=++ind, num1[ind]=u;
if(son[u]) dfs2(son[u], tp);
for(pair<int, int> v : l1[u]) if(v.t!=son[u]&&v.t!=fa[u]) dfs2(v.t, v.t);
}
int ask(int u, int v, int w){
int ans=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) u^=v, v^=u, u^=v;
ans=max(ans, query(num[top[u]], num[u], 1));
change(num[top[u]], num[u], w, 1); u=fa[top[u]];
}
if(dep[u]<dep[v]) u^=v, v^=u, u^=v;
change(num[v]+1, num[u], w, 1); ans=max(ans, query(num[v]+1, num[u], 1));
return ans;
}
int f[N];
bool vis[N];
int find(int x) { return x==f[x] ? x : f[x]=find(f[x]); }
inline void pre(){
sort(l+1, l+1+m); int cnt=0, u, v;
for(int i=1; i<=n; ++i) f[i]=i;
for(int i=1; i<=m; ++i){
u=find(l[i].f), v=find(l[i].t);
if(v!=u) f[u]=v;
}
int ul=0;
for(int i=1; i<=n; ++i) if(find(1)==find(i)) vis[i]=1, ul++;
for(int i=1; i<=n; ++i) f[i]=i;
for(int i=1; i<=m&&cnt<ul-1; ++i){
if(!vis[l[i].f]||!vis[l[i].t]) continue;
u=find(l[i].f); v=find(l[i].t);
if(u==v) continue; ++cnt;
f[u]=v; u=l[i].f, v=l[i].t; l[i].ul=1;
l1[u].push_back(make_pair(v, l[i].w));
l1[v].push_back(make_pair(u, l[i].w));
}
dfs1(1, 0); dfs2(1, 1); built(1, ul, 1);
}
inline void solve(){
for(int i=1; i<=m; ++i){
if(l[i].ul) continue;
l[i].ans=ask(l[i].f, l[i].t, l[i].w);
}
dfs3(INF, 1);
for(int i=1; i<=m; ++i){
if(!l[i].ul||!vis[l[i].f]||!vis[l[i].t]) continue;
if(fa[l[i].f]==l[i].t) l[i].ans=val[l[i].f];
else l[i].ans=val[l[i].t];
}
sort(l+1, l+1+m, cmp);
for(int i=1; i<=m; ++i){
if(l[i].ans==INF) printf("-1 ");
else if(!l[i].ans) printf("0 ");
else printf("%d ", --l[i].ans);
}
printf("\n");
}
int main(void){
n=read(); m=read(); a=read();
int x, y, z;
for(int i=1; i<=m; ++i){
x=read(), y=read(), z=read();
l[i]=(EDGE){x, y, z, i, 0, 0};
}
pre(); solve();
return 0;
}
当然也可以用 \(LCT\) 不过我懒得写了,存下巨佬的代码。
标签:ch,return,17,int,num,恩偶,read,挨批,getchar 来源: https://www.cnblogs.com/CTcode/p/NOIP_17.html