NOIP2023模拟2联测23 T2 害怕

好像写了一种出题人意料之外的算法。

思路

在生成树上加入白边,白边和若干条蓝色边形成环,环上的蓝色边必须要分配比该白色边更小的边权(最小生成树)。

给每一条边一个分配优先级,优先级的数越小,优先级越高,分配的边权越小。

一开始所有边的优先级的数都等于自己本身的输入顺序。

不断加入白边,与白边形成环的蓝边,优先级有一下两个选择:1.选自己的输入顺序;2.选白边的输入顺序。

每一条边都希望自己分配的边权更小,所以该边会上述选择较小者。

正确性证明:

如果蓝色边边权比白色边小:不做改动,依旧分配之前的边权。

如果蓝色边边权比白色边大:如果不做改动,那么白色边分配的边权要等到,形成环的蓝边边权在原优先级上分配结束,才能分配自己。那么可能会有优先级比白边低的边分配到比白色边更小的值,这肯定是不优的(白色边排序更靠前,边权越低,带来字典序越小)。

这里也可以距离证明一下,正确性是有保证的。

那么维护两点之间路径边的优先级即可,为了方便实现,可以边权压点权,使用树剖。

树剖的线段树维护的是该段内的优先级的分配情况,发现如果从小到大枚举白色边形成环,那么所有的蓝色边的优先级最多被更改一次(或者说只被白色边找到一次,因为后面找到这条蓝边的优先级肯定没有之前的高)。

维护两点路径可以看做求 \(LCA\)。

不过线段树后面被卡时限了,发现求 \(LCA\) 是若干个完整的链加三四个分裂的链,完整的链实际上查过一次就不用查了,可以大大优化复杂度。

线段树实现:

#include<bits/stdc++.h>
using namespace std; #define fi first
#define se second const int maxn=5e5+5; struct node1
{
int to,nxt,id;
}edge[maxn*2];
struct node2
{
int u,v,id;
}ed[maxn]; int n,m,tot,cnt,cok,ct,cdq;
int head[maxn],hso[maxn],sz[maxn],p[maxn],fp[maxn],fa[maxn],top[maxn],ans[maxn],deep[maxn],cis[maxn]; bool vis[maxn]; pair<int,int>dq[maxn]; vector< pair<int,int> >vec[maxn]; inline int read() {
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
inline void write(int X)
{
if(X<0) {X=~(X-1); putchar('-');}
if(X>9) write(X/10);
putchar(X%10+'0');
} inline void add(int x,int y,int z)
{
tot++;
edge[tot].to=y;
edge[tot].nxt=head[x];
edge[tot].id=z;
head[x]=tot;
} inline void dfs1(int u)
{
sz[u]++;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa[u]) continue;
fa[v]=u;
deep[v]=deep[u]+1;
cis[v]=edge[i].id;
dfs1(v);
sz[u]+=sz[v];
if(sz[v]>sz[hso[u]]) hso[u]=v;
}
return ;
}
inline void dfs2(int u,int tp)
{
if(!u) return ;
p[u]=++cok;
fp[cok]=u;
top[u]=tp;
dfs2(hso[u],tp);
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==fa[u]||v==hso[u]) continue;
dfs2(v,v);
}
return ;
} inline void lca(int x,int y,int t)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
vec[p[top[x]]].push_back(make_pair(t,p[x]));
x=fa[top[x]];
}
if(deep[x]<deep[y]) swap(x,y);
vec[p[y]+1].push_back(make_pair(t,p[x]));
return ;
} int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
{
int x,y,op;
x=read(),y=read(),op=read();
if(op) add(x,y,i),add(y,x,i);
else
{
cnt++;
ed[cnt].u=x;
ed[cnt].v=y;
ed[cnt].id=i;
}
} deep[1]=1;
dfs1(1);
dfs2(1,1); for(int i=1;i<=cnt;i++)
lca(ed[i].u,ed[i].v,ed[i].id); priority_queue< pair<int,int> ,vector< pair<int,int> > , greater< pair<int,int> > >tq;
for(int i=1;i<=n;i++)
{
for(int j=0;j<vec[i].size();j++)
{
if(!tq.empty())
{
if(tq.top().first<vec[i][j].first&&tq.top().second>=vec[i][j].second) continue;
}
tq.push(vec[i][j]);
}
if(tq.empty())
{
dq[++cdq]=make_pair(cis[fp[i]],cis[fp[i]]);
}
else
{
while(!tq.empty())
{
if(tq.top().second<i) tq.pop();
else break;
}
if(tq.empty()) dq[++cdq]=make_pair(cis[fp[i]],cis[fp[i]]);
else dq[++cdq]=make_pair(min(cis[fp[i]],tq.top().first),cis[fp[i]]);
}
}
for(int i=1;i<=cnt;i++) dq[++cdq]=make_pair(ed[i].id,m+1); sort(dq+1,dq+cdq+1);
for(int i=1;i<=cdq;i++)
{
if(dq[i].se==0) continue;
ct++;
int k=dq[i].se;
if(k==m+1) k=dq[i].fi;
ans[k]=ct;
}
for(int i=1;i<=m;i++) write(ans[i]),printf(" ");
}

NOIP2023模拟2联测23 T2 害怕的更多相关文章

  1. [NOIP2018模拟赛10.23]发呆报告

    闲扯 考场看了眼题目感觉很难,一个小时敲完了所有暴力...嗯然后就在那里发呆什么事也没做 T3考场上把数据结构想了个遍都不会完成1操作,现在看这种思路其实之前也接触过... 比较玄学的一件事情就是T1 ...

  2. [NOI.AC省选模拟赛3.23] 染色 [点分治+BFS序]

    题面 传送门 重要思想 真的是没想到,我很久以来一直以为总会有应用的$BFS$序,最终居然是以这种方式出现在题目中 笔记:$BFS$序可以用来处理限制点对距离的题目(综合点分树使用) 思路 本题中首先 ...

  3. [jzoj 6080] [GDOI2019模拟2019.3.23] IOer 解题报告 (数学构造)

    题目链接: https://jzoj.net/senior/#main/show/6080 题目: 题意: 给定$n,m,u,v$ 设$t_i=ui+v$ 求$\sum_{k_1+k_2+...+k_ ...

  4. Wannafly挑战赛23 T2游戏 SG函数

    哎,被卡科技了,想了三个小时,最后还是大佬给我说是\(SG\)函数. \(SG\)函数,用起来很简单,证明呢?(不可能的,这辈子都是不可能的) \(SG\)定理 游戏的\(SG\)函数就是各个子游戏的 ...

  5. [NOI.AC省选模拟赛3.23] 集合 [数学]

    题面 传送门 一句话题意: 给定$n\leq 1e9,k\leq 1e7,T\leq 1e9$ 设全集$U=\lbrace 1,2,3,...n\rbrace $,求$(min_{x\in S}\lb ...

  6. Qbxt 模拟题 day2(am) T2 jian

    [问题描述] 有N个数,随机选择一段区间,如果这段区间的所有数的平均值在[L,R]中则你比较厉害.求你比较厉害的概率. [输入格式] 第一行有三个数N, l, r,含义如上描述. 接下来一行有N个数代 ...

  7. NOIP模拟赛(by hzwer) T2 小奇的序列

    [题目背景] 小奇总是在数学课上思考奇怪的问题. [问题描述] 给定一个长度为 n 的数列,以及 m 次询问,每次给出三个数 l,r 和 P, 询问 (a[l'] + a[l'+1] + ... + ...

  8. 模拟赛DAY 2 T2不老梦

    [题目背景] 于万人中万幸得以相逢,刹那间澈净明通. 成为我所向披靡的勇气和惶恐,裂山海,堕苍穹. 爱若执炬迎风,炽烈而哀恸,诸般滋味皆在其中. 韶华宛转吟诵,苍凉的光荣,急景凋年深情难共. ——银临 ...

  9. 2.17NOIP模拟赛(by hzwer) T2 小奇的序列

    [题目背景] 小奇总是在数学课上思考奇怪的问题. [问题描述] 给定一个长度为 n 的数列,以及 m 次询问,每次给出三个数 l,r 和 P, 询问 (a[l'] + a[l'+1] + ... + ...

  10. 【算法】dsu on tree初探

    dsu on tree的本质是树上的启发式合并,它利用启发式合并的思想,可以将O(N^2)的暴力优化成O(NlogN),用于不带修改的子树信息查询. 具体如何实现呢?对于一个节点,继承它重儿子的信息, ...

随机推荐

  1. 【YashanDB知识库】共享集群YAC换IP

    [标题]共享集群YAC换IP [需求分类]安装部署,配置变更 [关键字]安装部署,更换IP,运维,配置变更,高可用,YAC [需求描述]客户需要将已经部署的YAC集群更换IP,从测试网段切换生产网段 ...

  2. 合合信息亮相新加坡科技周——Big Data & AI World Expo展示AI驱动文档数字化的前沿能力

    合合信息亮相新加坡科技周--Big Data & AI World Expo展示AI驱动文档数字化的前沿能力   展会规模背景: 2023年10月11日-12日,合合信息在TECH WEEK ...

  3. JavaScript Library – Swiper

    前言 官网已经有很好的教程了, 这篇只是记入一些我用过的东西和冷门知识. 参考 官网安装 官网 Demo 安装 yarn add swiper JS import Swiper from 'swipe ...

  4. Vue——前端框架

    Vue    Vue 快速入门    <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  5. 【赵渝强老师】Docker Swarm实现服务的滚动更新

    一.什么是Docker Swarm? Docker Swarm是Docker官方提供的一款集群管理工具,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口统一管理这些Docker主机 ...

  6. 2021年3月国产数据库排行榜:OceanBase勇夺亚军 神舟挺进20强!

    1 新春排行 2021年3月榜单新鲜出炉,同2月相比,本月榜单中十强产品还是原来的面孔,其中3款产品取得了新的名次,榜单座次调整超过半数.前三甲仍然是TiDB.OceanBase.达梦. 冠军:TiD ...

  7. 墨天轮访谈 | OceanBase 白超:海量数据管理,为什么选择OceanBase?

    分享嘉宾:白超(大窑) OceanBase解决方案架构师.前蚂蚁集团数据库团队DBA专家 整理:墨天轮社区 导 读 大家好,我是白超(花名:大窑),在过去的几年中,作为蚂蚁集团数据库SRE团队成员,经 ...

  8. kotlin更多语言结构——>反射

    类引用 最基本的反射功能是获取 Kotlin 类的运行时引用.要获取对静态已知的 Kotlin 类的引用,可以使用 类字面值 语法 val c = MyClass::class 请注意,Kotlin ...

  9. day11-基本运算符

    运算符 java语言支持如下运算符: 优先级 ( 多敲,多练习 ) 算术运算符:+,-,*,/,%(模运算:取余),++,--  package operator; ​ public class De ...

  10. for循环、break和continue、二重循环

    循环语句 循环语句可以反复多次执行同一组语句,for关键字可以用来编写循环:可以在for循环里让一个变量依次代表一组数字,然后使用同一组语句处理这个变量代表的每个数字.这个变量叫做循环变量,按照统一的 ...