2025省选模拟5 T1
看到大家使用优美的记搜方法过掉 T1,我来介绍一种较为独特的方法。
众所周知,我们只需要处理 \(2m\) 个接口(以下称为关键点)。我们将每个关键点拆分成 \(O(n)\) 条信息,分别记录这个点在每个阶段所在的树以及从上个状态到下一阶段是从前半子树(标号不增加的子树)还是后半子树合并来的。例如:我们先把 \(T_0\) 的 \(0\) 号节点连到自己形成 \(T_1\),经过一系列操作后将 \(T_1\) 的 \(1\) 号节点和 \(T_a\) 的某个节点连接形成 \(T_b\),最终 \(T_1\) 的 \(1\) 号节点在 \(T_b\) 上成为了关键点,则我们记录的各个状态所在的树的信息为 \(0 \rightarrow 1 \rightarrow b\),分别是作为后半子树和前半子树合并的。这里有个反常的细节:对于两个不同关键点,如果他们可以到达同一状态,这个状态应当记录多次而非一次。这是一个显然的性质,因为我们把不同关键点的完整前驱状态序列独立地存了起来,但这是我们未来操作正确性的重要条件。
考虑 \(T_a\) 和 \(T_b\) 合并为 \(T\):答案等于 \(T_a\) 和 \(T_b\) 的答案加上两颗树以其对应的接口(即关键点)为根所有点的深度之和与对面点的个数的乘积(分解 \((a+c)+(a+d)+(b+c)+(b+d)=2(a+b)+2(c+d)\),其中 \(a,b\) 为 \(T_a\) 中的,\(c,d\) 反之),再将上两颗树的大小乘积(新形成的路径条数)乘上新边权值。某个点的深度之和需要加上另一棵树接口处的深度之和加上另一棵树节点个数乘上这个关键点与另一棵树接口间的距离。综上所述,我们需要维护每棵树的答案,大小,每个关键点为根的深度之和与两个关键点间距离。前两者很容易维护。先来考虑点间距离。对于每个关键点,维护指针表示这个点的当前状态。每次找到下一状态是 \(T\) 且不是接口的节点,分别加入前半棵树或后半棵树的集合。每次取出两个集合中的点更新另一集合中的每一个点(可以不用处理除了另一棵树内下一状态是 \(T\) 的点以外的点,因为这样的点未来一定与前者无关,即使他是错的也不影响答案。)。更新方式为用两点加上到本树的接口距离再加上新边权值。接下来更新子树内深度和的过程就很显然。为什么要排掉接口?因为这两个接口未来不会再用,对答案没有影响,算上可能会有意想不到的错误(比如合并同一颗树,可能导致同一接口有一个值为新加边的到自己的距离,使得后面距离多加)。
这个解法无需使用递归、哈希表,时间 \(O(n^3)\),空间\(O(n^2)\),虽说码量稍微大些。
Code
#include<bits/stdc++.h>
using namespace std;
const long long p=1000000007;
struct node{
bool opt[800];
int tr[800],tot,cur;
}dot[800];
struct stct{
int sttr,edtr,st,ed;
long long stpt,edpt,val;
}ask[800];
int n,cnt;
long long size[512],sdep[1024],dist[800][800],szst[512],ans[512];
inline void gen(int x,long long x1,int y){
dot[++cnt].tr[0]=y;
for(long long tx=x,tx1=x1;tx;){
dot[cnt].tr[++dot[cnt].tot]=tx;
if(tx1>=szst[tx]) tx1-=szst[tx],tx=ask[tx].edtr;
else tx=ask[tx].sttr,dot[cnt].opt[dot[cnt].tot]=1;
}
++dot[cnt].tot;
int ulim=dot[cnt].tot>>1;
for(int i=0;i<=ulim;++i){
swap(dot[cnt].tr[i],dot[cnt].tr[dot[cnt].tot-i]);
swap(dot[cnt].opt[i],dot[cnt].opt[dot[cnt].tot-i]);
}
}
vector<int> v1,v2;
int main(){
freopen("loquat.in","r",stdin);
freopen("loquat.out","w",stdout);
scanf("%d",&n);
size[0]=1;
for(int i=1;i<=n;++i){
scanf("%d%d%lld%lld%lld",&ask[i].sttr,&ask[i].edtr,&ask[i].stpt,&ask[i].edpt,&ask[i].val);
szst[i]=size[ask[i].sttr];
size[i]=szst[i]+size[ask[i].edtr];
gen(ask[i].sttr,ask[i].stpt,i);
gen(ask[i].edtr,ask[i].edpt,i);
}
memset(size,0,sizeof(size));
size[0]=1;
for(int i=1,x=1,y=2;i<=n;++i,x+=2,y+=2){
int tx=ask[i].sttr,ty=ask[i].edtr;
ans[i]=((((sdep[x]*size[ty]%p+sdep[y]*size[tx]%p)%p+ans[tx])%p+ans[ty])%p+size[tx]*size[ty]%p*ask[i].val%p)%p;
printf("%lld\n",ans[i]);
size[i]=(size[tx]+size[ty])%p;
for(int j=1;j<=cnt;++j){
if(j==x||j==y) continue;
if(dot[j].tr[dot[j].cur+1]==i){
if(dot[j].opt[dot[j].cur+1]) v1.emplace_back(j);
else v2.emplace_back(j);
}
}
for(auto j:v1){
dist[j][y]=dist[j][x]+ask[i].val;
if(dist[j][y]>=p) dist[j][y]-=p;
dist[y][j]=dist[j][y];
for(auto k:v2){
dist[j][k]=dist[j][x]+dist[k][y];
if(dist[j][k]>=p) dist[j][k]-=p;
dist[j][k]+=ask[i].val;
if(dist[j][k]>=p) dist[j][k]-=p;
dist[k][j]=dist[j][k];
}
}
for(auto j:v2){
dist[j][x]=dist[j][y]+ask[i].val;
if(dist[j][x]>=p) dist[j][x]-=p;
dist[x][j]=dist[j][x];
for(auto k:v1){
dist[j][k]=dist[j][y]+dist[k][x];
if(dist[j][k]>=p) dist[j][k]-=p;
dist[j][k]+=ask[i].val;
if(dist[j][k]>=p) dist[j][k]-=p;
dist[k][j]=dist[j][k];
}
}
for(auto j:v1){
sdep[j]=((sdep[j]+dist[j][y]*size[ty]%p)%p+sdep[y])%p;
++dot[j].cur;
}
for(auto j:v2){
sdep[j]=((sdep[j]+dist[j][x]*size[tx]%p)%p+sdep[x])%p;
++dot[j].cur;
}
v1.clear();
v2.clear();
}
return 0;
}
2025省选模拟5 T1的更多相关文章
- 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解
今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...
- 5.15 省选模拟赛 T1 点分治 FFT
LINK:5.15 T1 对于60分的暴力 都很水 就不一一赘述了. 由于是询问所有点的这种信息 确实不太会. 想了一下 如果只是询问子树内的话 dsu on tree还是可以做的. 可以自己思考一下 ...
- NOI 2019 省选模拟赛 T1【JZOJ6082】 染色问题(color) (多项式,数论优化)
题面 一根长为 n 的无色纸条,每个位置依次编号为 1,2,3,-,n ,m 次操作,第 i 次操作把纸条的一段区间 [l,r] (l <= r , l,r ∈ {1,2,3,-,n})涂成颜色 ...
- 洛谷[LnOI2019]长脖子鹿省选模拟赛t1 -> 快速多项式变换
快速多项式 做法:刚拿到此题有点蒙,一开始真没想出来怎么做,于是试着去自己写几个例子. 自己枚举几种情况之后就基本看出来了,其实本题中 n 就是f(m)在m进制下的位数,每项的系数就是f(m)在m进制 ...
- 5.20 省选模拟赛 T1 图 启发式合并 线段树合并 染色计数问题
LINK:图 在说这道题之前吐槽一下今天的日子 520 = 1+1+4+514. /cy 这道题今天做的非常失败 一点分都没拿到手 关键是今天的T3 把我整个人给搞崩了. 先考虑 如果得到了这么一张图 ...
- 5.19 省选模拟赛 T1 小B的棋盘 双指针 性质
LINK:小B的棋盘 考试的时候没有认真的思考 导致没做出来. 容易发现 当k>=n的时候存在无限解 其余都存在有限解 对于30分 容易想到暴力枚举 对称中心 然后 n^2判断. 对于前者 容易 ...
- 【2018.06.26NOIP模拟】T1纪念碑square 【线段树】*
[2018.06.26NOIP模拟]T1纪念碑square 题目描述 2034年,纪念中学决定修建校庆100周年纪念碑,作为杰出校友的你被找了过来,帮校方确定纪念碑的选址. 纪念中学的土地可以看作是一 ...
- 【2020.11.28提高组模拟】T1染色(color)
[2020.11.28提高组模拟]T1染色(color) 题目 题目描述 给定 \(n\),你现在需要给整数 \(1\) 到 \(n\) 进行染色,使得对于所有的 \(1\leq i<j\leq ...
- 省选模拟赛 4.26 T1 dp 线段树优化dp
LINK:T1 算是一道中档题 考试的时候脑残了 不仅没写优化 连暴力都打挂了. 容易发现一个性质 那就是同一格子不会被两种以上的颜色染.(颜色就三种. 通过这个性质就可以进行dp了.先按照左端点排序 ...
- NOI.AC省选模拟赛第一场 T1 (树上高斯消元)
link 很容易对于每个点列出式子 \(f_{x,y}=(f_{x,y-1}+f_{x,y}+f_{x,y+1}+f_{x+1,y})/4\)(边角转移类似,略) 这个转移是相互依赖的就gg了 不过你 ...
随机推荐
- post数据到第三方,中文乱码
1.项目中发现 测试环境 推送正文,数据正常 2.生产到腾讯云之后,中文推送过去乱码,但是post 接口的 时候,指定了 编码格式. 3.后查看日志,发现日志中记录的中文就是乱码 4.排查cs代码文件 ...
- JBoltAI Function Call技术解析:如何实现AI模型与企业系统的无缝对话
JBoltAI Function Call技术解析: 如何实现AI模型与企业系统的无缝对话 在企业级AI应用开发中,如何让大模型能力与现有系统高效协同一直是技术难点.JBoltAI框架通过Functi ...
- Java实体类如何映射到json数据(驼峰映射到json中的下划线)
Java实体类(驼峰)映射到json数据(下划线) 由于经常需要接收前端的json数据,而json数据一般都是使用下划线命名的.后端又不太建议使用map接收,所以就需要用到使用自定义类来接收(如果参数 ...
- Scrcpy使用入门
1.下载Scrcpy GitHub地址:https://github.com/Genymobile/scrcpy 网盘地址:https://pan.baidu.com/s/1NKosSkQJLbmhz ...
- 一文速通 Python 并行计算:07 Python 多线程编程-线程池的使用和多线程的性能评估
一文速通 Python 并行计算:07 Python 多线程编程-线程池的使用和多线程的性能评估 摘要: 本文介绍了 Python 线程池(ThreadPoolExecutor)的使用方法,包括线程池 ...
- symfony4怎么切换到开发环境的问题
1.根目录下有.env文件,约17行有这句: APP_ENV=dev 默认开发环境 prod为生产环境 2..env.local.php文件(如果有)会覆盖.env的配置
- git仓库常用git命令&极速入门教程
简易的命令行入门教程: Git 全局设置: git config --global user.name "yourName" git config --global user.em ...
- IIS的垃圾回收对后台任务及隐形后台任务的影响
IIS的垃圾回收引起的影响 错误排查 现象:在.net core api里创建的BackgroundService定义rabbitmq消费的逻辑,在一段时间运行后经常会出现消费任务中断,在日志里找了很 ...
- 使用PowerShell开发脚本程序进行批量SVN提交
使用PowerShell开发脚本程序进行批量SVN提交 随着软件开发的不断进步,版本控制系统如Subversion (SVN) 成为了团队协作和代码管理的重要工具.当需要一次性提交大量文件时,手动操作 ...
- 7.9K star!跨平台开发从未如此简单,这个开源框架让APP开发效率飙升!
嗨,大家好,我是小华同学,关注我们获得"最新.最全.最优质"开源项目和高效工作学习方法 Lynx 是一个革命性的跨平台开发框架,使用 TypeScript 开发即可同时构建 iOS ...