\(\color{white}{\mathbb{霞光划破暗淡天际,月影彷徨,鸡鸣仿佛,冀之以继往开来,名之以:黎明}}\)

今天似乎取得了有史以来最好的成绩~

前两名都 A 掉了 \(t3\),然鹅 \(t3\) 上去就被我弃了……

前两天部分分都写得比较顺利

\(t1\) 一眼以为 \(bitset\) 裸题,开了 \(6e4 * 6e4\) 直接自信提交,后来一算才发现空间炸了

但是不记得一位 \(bitset\) 是多大,以为和 \(bool\) 一样,只能开 \(10^4 * 10^4\),没敢打另外 20% 的部分分,暴挂20分

\(t2\) 网络流板子忘得差不多了,口胡了还几次才过了样例


A. 世界线

读懂题很快就能看出来是 \(bitset\),但是空间比较卡

首先,\(bitset\) 是每8位占用一个字节,一次运算复杂度为 \(n/32\)

那么其实前 \(60%\) 都是可以轻松水过去的

发现最后两个点的理论空间都比能开下的 \(bitset\) 大一倍,那么可以采用把所有点分成两部分的方式统计,\(bitset\) 只开一半,第一次统计所有点能到达的 \(\le n/2\) 的点的个数,再来一次统计能到达的 \(>n/2\) 的点的个数,直接相加即可

代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=6e4+5;
const int maxm=1e6+5;
int n,m,deg[maxn],x,y,hd[maxn],cnt,limit,out[maxn];
bitset<maxn/2>vis[maxn];
long long ans;
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
struct Edge{
int nxt,to;
}edge[maxm];
void add(int u,int v){
edge[++cnt].nxt=hd[u];
edge[cnt].to=v;
hd[u]=cnt;
return ;
}
void topsort(int op){
queue<int>q;
for(int i=1;i<=n;i++){
if(!deg[i])q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=hd[u];i;i=edge[i].nxt){
int v=edge[i].to;
vis[v]|=vis[u];
if(!(--deg[v])){
q.push(v);
}
}
}
return ;
}
int main(){
n=read();
m=read();
for(int i=1;i<=m;i++){
x=read();
y=read();
deg[x]++;
add(y,x);
}
for(int i=1;i<=n;i++){
ans-=deg[i]+1;
out[i]=deg[i];
}
limit=n/2;
for(int i=1;i<=limit;i++){
vis[i][i]=1;
}
topsort(0);
for(int i=1;i<=n;i++){
ans+=vis[i].count();
// cout<<vis[i].count()<<endl;
vis[i].reset();
deg[i]=out[i];
}
// vis.reset();
for(int i=limit+1;i<=n;i++){
vis[i][i-limit]=1;
}
topsort(1);
for(int i=1;i<=n;i++){
// cout<<vis[i].count()<<" ";
ans+=vis[i].count();
}
cout<<ans;
return 0;
} /*
5 5
1 2
1 3
2 3
3 4
4 5
*/

B. 时间机器

说实话考场上没有认真看懂题,光用网络流水了一下居然拿到了70分

这道题正解贪心

考虑所有元件和节点按左端点第一关键字右端点第二关键字排序后,那么右端点靠左的元件越容易用不上,所以尽可能优先选取右端点靠左的元件

那么对于一个节点拥有一个左右端点满足条件的候选集合,考虑左端点对于后面的节点都是可用的,但是右端点可能会被淘汰掉,那么就选择右端点最靠左的一个元件进行匹配

这个可以用 \(set\) 实现

注意这道题一开始一直被卡常,后来发现 \(s.lower\_bound(xxx)\) 比 \(lower\_bound(s.begin(),s.end(),xxx)\) 快好多

代码实现
#include<bits/stdc++.h>
using namespace std;
//#define int long long
const int maxn=1e6+5;
int t,n,m,tp;
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
struct Th{
int l,r,num;
}a[maxn],b[maxn];
struct Node{
int fi;
mutable int se;
Node(int x=0,int y=0):fi(x),se(y){}
};
bool operator < (const Node &x,const Node &y){
return x.fi!=y.fi?x.fi<y.fi:x.se<y.se;
}
multiset<Node>s;
bool operator < (const Th &x,const Th &y){
return x.l==y.l?x.r<y.r:x.l<y.l;
}
void solve(){
tp=1;
for(int i=1;i<=n;i++){
while(tp<=m&&b[tp].l<=a[i].l){
s.insert(Node(b[tp].r,b[tp].num));
tp++;
}
while(a[i].num){
multiset<Node>::iterator it=s.lower_bound(Node(a[i].r,0));
if(it==s.end()){
puts("No");
return ;
}
if(a[i].num < it->se){
it->se -= a[i].num;
break;
}
a[i].num-= it->se;
s.erase(it);
}
}
puts("Yes");
}
signed main(){
t=read();
while(t--){
n=read();
m=read();
for(int i=1;i<=n;i++){
a[i].l=read();
a[i].r=read();
a[i].num=read();
}
for(int i=1;i<=m;i++){
b[i].l=read();
b[i].r=read();
b[i].num=read();
}
sort(a+1,a+n+1);
sort(b+1,b+m+1);
s.clear();
solve();
}
return 0;
} /*
3
2 2
1 2 2
1 2 1
1 2 1
1 2 2
2 2
1 4 2
3 5 1
1 4 2
2 5 1 3 2
1 3 1
2 4 1
3 5 1
1 3 2
2 5 1 */

C. weight

考完试 cyh 说和题单上的 Mst 这道题基本上是一样的,真后悔当时没看这道题

首先把最小生成树建出来,然后树边和非树边分别讨论

如果是非树边,那么答案为生成树上两端点路径上边权最大值 -1

如果是树边,则是所有和这条边有关的非树边的最小值 -1

可以采用树剖,每条非树边查询一次修改一次即可

cyh 的LCT理论复杂度少一个 \(log\),也非常好维护

注意判不在连通块里的边(可以用并查集判断),树剖需要边化点,更新时不能选上面的那个点

于是一直调一直改写了将近300行……

代码实现

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const int maxm=4e5+5;
//const int inf=
int n,m,ans[maxn],x,y,w,op;
int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
namespace p2{
int hd[maxn],cnt,cnt1,re[maxn],fa[maxn],tot,id[maxn],pa[maxn],siz[maxn],son[maxn],dep[maxn],tp[maxn],val[maxn];
struct Edge{
int nxt,to,val,id;
}edge[maxm];
void add(int u,int v,int w,int num){
edge[++cnt].nxt=hd[u];
edge[cnt].to=v;
edge[cnt].val=w;
edge[cnt].id=num;
hd[u]=cnt;
return ;
}
struct Ch{
int from,to,id,val;
}link[maxm];
void make(int u,int v,int w,int num){
link[++cnt1].to=v;
link[cnt1].from=u;
link[cnt1].val=w;
link[cnt1].id=num;
return ;
}
void dfs(int u){
// cout<<u<<" "<<endl;
siz[u]=1;
for(int i=hd[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u])continue;
dep[v]=dep[u]+1;
fa[v]=u;
val[v]=edge[i].val;
pa[v]=edge[i].id;
// cout<<"hhh "<<v<<" "<<pa[v]<<endl;
dfs(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
return ;
}
void dfs1(int u,int top){
tp[u]=top;
id[u]=++tot;
re[tot]=u;
// cout<<u<<" ";
if(son[u])dfs1(son[u],top);
for(int i=hd[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u]||v==son[u])continue;
dfs1(v,v);
}
return ;
}
struct Seg{
int l,r,mx,lazy;
}t[maxn*4];
void update(int p){
t[p].mx=max(t[p<<1].mx,t[p<<1|1].mx);
return ;
}
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
t[p].lazy=0x3f3f3f3f;
if(l==r){
t[p].mx=val[re[l]];
// cout<<"kkk "<<l<<" "<<val[id[l]]<<endl;
return ;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
update(p);
return ;
}
int ask(int p,int l,int r){
if(l>r)return 0;
if(t[p].l>=l&&t[p].r<=r)return t[p].mx;
int mx=0;
int mid=t[p].l+t[p].r>>1;
if(l<=mid)mx=ask(p<<1,l,r);
if(r>mid)mx=max(mx,ask(p<<1|1,l,r));
return mx;
}
int ques(int x,int y){
int mx=0;
// cout<<"hhh "<<endl;
while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]])swap(x,y);
// cout<<"ppp "<<id[tp[x]]<<" "<<id[x]<<endl;
mx=max(mx,ask(1,id[tp[x]],id[x]));
x=fa[tp[x]];
}
// cout<<mx<<endl;
if(dep[x]>dep[y])swap(x,y);
// cout<<"ppp "<<id[x]+1<<" "<<id[y]<<endl;
mx=max(mx,ask(1,id[x]+1,id[y]));
// cout<<id[x]<<" "<<id[y]<<endl;
return mx;
}
void ch(int p,int l,int r,int w){
if(l>r)return ;
if(t[p].l>=l&&t[p].r<=r){
t[p].lazy=min(t[p].lazy,w);
return ;
}
int mid=t[p].l+t[p].r>>1;
if(l<=mid)ch(p<<1,l,r,w);
if(r>mid)ch(p<<1|1,l,r,w);
return ;
}
void change(int x,int y,int w){ while(tp[x]!=tp[y]){
if(dep[tp[x]]<dep[tp[y]])swap(x,y); ch(1,id[tp[x]],id[x],w);
x=fa[tp[x]];
}
// cout<<mx<<endl;
if(dep[x]>dep[y])swap(x,y); ch(1,id[x]+1,id[y],w);
return ;
}
void spread(int p){
if(t[p].l==t[p].r){
// cout<<t[p].l<<" "<<re[t[p].l]<<" "<<pa[re[t[p].l]]<<endl;
ans[pa[re[t[p].l]]]=t[p].lazy;
return ;
}
t[p<<1].lazy=min(t[p<<1].lazy,t[p].lazy);
t[p<<1|1].lazy=min(t[p<<1|1].lazy,t[p].lazy);
spread(p<<1);
spread(p<<1|1);
return ;
}
void start(){
dfs(1);
pa[1]=m+1;
dfs1(1,1);
build(1,1,n);
// for(int i=1;i<=n;i++){
// cout<<pa[i]<<endl;
// }
// cout<<endl;
// cout<<"hhh ";
for(int i=1;i<=cnt1;i++){
int x=link[i].from;
int y=link[i].to;
// cout<<link[i].id<<" "<<x<<" "<<y<<" "<<link[i].val<<endl;
ans[link[i].id]=ques(x,y);
// flag[link[i].id];
// cout<<ans[link[i].id]<<endl;
// cout<<link[i].id<<" "<<ans[link[i].id]<<endl;
change(x,y,link[i].val);
}
spread(1);
return ;
}
}
namespace p1{
int hd[maxn],cnt,fa[maxn];
struct Edge{
int nxt,to,from,val,id;
}edge[maxm],edge1[maxm];
void add(int u,int v,int w){
edge[++cnt].nxt=hd[u];
edge[cnt].to=v;
edge[cnt].from=u;
edge[cnt].val=w;
return ;
}
bool cmp(Edge a,Edge b){
return a.val<b.val;
}
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void kruscal(){
sort(edge+1,edge+m+1,cmp);
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
int u=edge[i].from;
int v=edge[i].to;
x=find(u);
y=find(v);
if(x!=y){
fa[x]=y;
// cout<<u<<" "<<v<<" "<<edge[i].val<<" "<<edge[i].id<<endl;
p2::add(u,v,edge[i].val,edge[i].id);
p2::add(v,u,edge[i].val,edge[i].id);
}
else{
// cout<<u<<" "<<v<<" "<<edge[i].val<<" "<<edge[i].id<<endl;
p2::make(u,v,edge[i].val,edge[i].id);
}
}
return ;
}
}
namespace p3{
int fa[maxn],tot,tot1,idx[maxn];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void pd(){
for(int i=1;i<=n;i++){
fa[i]=i;
}
for(int i=1;i<=m;i++){
int x=p1::edge[i].from;
int y=p1::edge[i].to;
x=find(x);
y=find(y);
if(x!=y)fa[x]=y;
}
for(int i=1;i<=m;i++){
p1::edge1[i]=p1::edge[i];
// cout<<find(p1::edge[i].from)<<" "<<find(1)<<endl;
if(find(p1::edge[i].from)!=find(1)&&find(p1::edge[i].to)!=find(1)){
ans[p1::edge[i].id]=1;
// cout<<"ppp "<<p1::edge[i].id<<endl;
tot++;
}
else idx[++tot1]=i;
}
p1::cnt=0;
memset(p1::hd,0,sizeof p1::hd);
for(int i=1;i<=tot1;i++){
p1::add(p1::edge1[idx[i]].from,p1::edge1[idx[i]].to,p1::edge1[idx[i]].val);
p1::edge[p1::cnt].id=p1::edge1[idx[i]].id;
}
m=tot1;
}
}
int main(){
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
n=read();
m=read();
op=read();
for(int i=1;i<=m;i++){
x=read();
y=read();
w=read();
p1::add(x,y,w);
p1::edge[p1::cnt].id=i;
}
// cout<<"hhh ";
// p3::tot1=m;
p3::pd();
// cout<<"ppp "<<m<<endl;
// cout<<"hhh ";
// for(int i=1;i<=m;i++){
// cout<<p1::edge[i].from<<" "<<p1::edge[i].to<<" "<<p1::edge[i].val<<" "<<p1::edge[i].id<<endl;
// }
p1::kruscal();
// cout<<"hhh ";
p2::start();
for(int i=1;i<=p3::tot+p3::tot1;i++){
if(ans[i]==0x3f3f3f3f)printf("-1 ");
else printf("%d ",ans[i]-1);
}
return 0;
} /*
5 4 0
4 5 2
1 2 1
2 3 2
3 1 3 */

\(\color{white}{\mathbb{困于心,衡于虑,而后作}}\)

noip模拟17的更多相关文章

  1. NOIP模拟17.9.21

    NOIP模拟17.9.21 3 58 145 201 161.5 样例输出21.6 数据规模及约定对于40% 的数据,N <= 20对于60% 的数据,N <= 1000对于100% 的数 ...

  2. NOIP模拟17.9.22

    NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥

  3. NOIP模拟 17.8.20

    NOIP模拟17.8.20 A.阶乘[题目描述]亲爱的xyx同学正在研究数学与阶乘的关系,但是他喜欢颓废,于是他就制作了一个和阶乘有关系的数学游戏:给出两个整数 n,m,令 t = !n,每轮游戏的流 ...

  4. NOIP模拟 17.8.18

    NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也 ...

  5. NOIP模拟 17.8.15

    NOIP模拟17.8.15 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...

  6. NOIP模拟 17.8.17

    NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 ...

  7. NOIP模拟 17.8.16

    NOIP模拟17.8.16 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...

  8. NOIP模拟 17.8.14

    NOIP模拟17.8.14 (天宇哥哥考察细心程度的题) [样例解释]如果删去第一个 1:在[3,1,2]中有 3 个不同的数如果删去 3:在[1,1,2]中有 2 个不同的数如果删去第二个 1:在[ ...

  9. NOIP模拟 17.9.28

    公交车[问题描述]市内有

  10. Noip模拟17 2021.7.16

    我愿称这场考试为STL专练 T1 世界线 巧妙使用$bitset$当作vis数组使用,内存不会炸,操作还方便,的确是极好的. 但是这个题如果不开一半的$bitset$是会炸内存的,因为他能开得很大,但 ...

随机推荐

  1. QML用Instantiator动态创建顶级窗口

    关键点 使用Model驱动Instantiator QML里面的hashmap: QQmlPropertyMap 上一次说到用 QQmlApplicationEngine 多次load的方式创建多个一 ...

  2. 未知高度-纯css实现水平垂直居中

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. C语言复习(六)----typedef 的作用

    typedef的作用 重命名变量:typedef unsigned int Uint;//可以使用Uint代替unsigned int 定义新的数据类型 typedef struct Books{ c ...

  4. TCP拥塞控制详解

    1. 拥塞原因与代价 拥塞的代价 当分组的到达速率接近链路容量时,分组经历巨大的排队时延. 发送方必须执行重传以补偿因为缓存溢出而丢弃的分组. 发送方在遇到大时延时进行的不必要重传会引起路由器利用其链 ...

  5. 如何在Spring Data MongoDB 中保存和查询动态字段

    原文: https://stackoverflow.com/questions/46466562/how-to-save-and-query-dynamic-fields-in-spring-data ...

  6. SpringMVC学习04(数据处理及跳转)

    4.数据处理及跳转 4.1结果跳转方式 4.1.1 ModelAndView 设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 . 页面 : {视图解析器前缀} ...

  7. 【笔记】使用scikit-learn解决回归问题

    使用sklearn解决回归问题 依然是加载数据 import numpy as np import matplotlib.pyplot as plt from sklearn import datas ...

  8. 嵌入式Linux可用的防火墙——iptables:实现ip白名单、mac地址白名单

    iptables是linux系统下的一个功能强大的模块,不仅可以用作防火墙,还可以实现NAT等众多路由功能.iptables的容器有很清晰的层次关系: 1. iptables是表的容器,iptable ...

  9. Pikachu-暴力破解模块

    一.概述 "暴力破解"是一攻击具手段,在web攻击中,一般会使用这种手段对应用系统的认证信息进行获取. 其过程就是使用大量的认证信息在认证接口进行尝试登录,直到得到正确的结果. 为 ...

  10. 旅游景点 Tourist Attractions 题解

    题面在这里 再次破了纪录,连做了3天... 让我们从头来一点一点分析 1.预处理 先看题面,乍一看貌似是个图论题,有n个点m条边,给定一些必须经过的点和强制经过顺序,求一条最短路 我们发现n和m都比较 ...