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了 不过你 ...
随机推荐
- UNIQUE VISION Programming Contest 2025 Spring (AtCoder Beginner Contest 398) (A~F) 补题+题解
A - Doors in the Center 签到题,直接构造即可. 点击查看代码 #include<bits/stdc++.h> using namespace std; #defin ...
- Efficient Scalable Multi-Party Private Set Intersection
论文学习:Efficient Scalable Multi-Party Private Set Intersection 这篇论文提出了一种基于双中心零共享(Bicentric Zero-Sharin ...
- JAVA基础之多线程四期--线程状态
一.线程的状态 二.线程生命周期分析图 三. 阻塞状态:具有cpu执行权,更待cpu空闲 休眠状态:不具有cpu执行权,cpu空闲时,也不能使用执行权
- 看过源码吗?说下 Spring 由哪些重要的模块组成?
是的,Spring源码可以深入分析,Spring框架是一个庞大的生态系统,包含多个模块,每个模块都为不同的功能提供支持.以下是Spring的主要模块及其职责: 1. Core Container(核心 ...
- EF Core 中避免 SQL 注入的三种写法
SQL 注入攻击可能会对我们的应用程序产生严重影响,导致敏感数据泄露.未经授权的访问和应用程序受损.EF Core 提供了三种内置机制来防止 SQL 注入攻击. 1.利用 LINQ 查询语法和参数化查 ...
- RMQ学习笔记
RMQ学习笔记 前言:这个算法无论是从适配性还是长度来说都很有实力... 关于 RMQ RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值. 详细信 ...
- MCP协议Streamable HTTP
一.概述 2025 年 3 月 26 日,模型上下文协议(Model Context Protocol,简称 MCP)引入了一项关键更新:用 Streamable HTTP 替代原先的 HTTP + ...
- freeswitch配置视频对接
概述 freeswitch是一款简单好用的VOIP开源软交换平台. 随着4G/5G网络的完善,视频呼叫的需求慢慢变多,本文介绍使用fs对接视频线路的配置方案. 环境 CentOS 7.9 freesw ...
- Axure RP大数据可视化大屏原型组件源文件
Axure RP大数据可视化大屏原型模板 大数据BI分析上大屏,在很多大企业和政府单位客户都需要,高新区市场监控等,那使用Axure RP做交互原型是必不可少的,有了大屏原型模板可做出不同风格和行业的 ...
- 提高Flutter应用性能的最佳实践
@charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...