【sdoi2013】森林 BZOJ 3123

本文介绍了一种使用主席树解决特定查询问题的方法,并通过启发式合并进行优化。该算法适用于处理动态连边操作下的第k大查询问题,通过实例详细讲解了实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Input

第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
 接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

Output

对于每一个第一类操作,输出一个非负整数表示答案。

Sample Input

1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6

Sample Output

2
2
1
4
2

思路

  恩。。近来发现主席树真的可以做很多事情呢=。=

  对于每一个节点建立主席树,记录从它到根节点的所有节点的权重,查询A->B的第k大即用A点主席树+B点主席树-LCA(A,B)的主席树-LCA(A,B)父亲的主席树。

  主席树求第k大很简单吧。。

  然后每次连边时我们暴力重建树,只是把小的树向大的树中插入。这个操作有个高端的名字*启发式合并*!!!

  每次连边的时候顺便维护一下求lca要用的信息就好OwO。

  只是记得要把不存在的父亲节点变成-1!!不然会有奇怪的错误TwT。。检查了我一个下午,大概就是本来一棵树的叶子节点被接在了另外一棵树上,那么它的有一些级的父亲会变得不存在TwT。

  窝会在代码里标出来的。。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <string>
  4 #include <cstdio>
  5 #include <cstdlib>
  6 #include <cmath>
  7 #include <algorithm>
  8 #include <queue>
  9 #include <stack>
 10 #include <map>
 11 #include <set>
 12 #include <list>
 13 #include <vector>
 14 #include <ctime>
 15 #include <functional>
 16 #define pritnf printf
 17 #define scafn scanf
 18 #define sacnf scanf
 19 #define For(i,j,k) for(int i=(j);i<=(k);(i)++)
 20 #define Clear(a) memset(a,0,sizeof(a))
 21 using namespace std;
 22 typedef unsigned int Uint;
 23 const int INF=0x3fffffff;
 24 ///==============struct declaration==============
 25 struct Node{
 26     Node *lc,*rc;
 27     int siz;
 28     Node (){lc=rc=NULL;siz=0;}
 29 };
 30 ///==============var declaration=================
 31 const int MAXN=100050;
 32 Node rem[MAXN*100];int top=0;
 33 #define new(Node) (&rem[top++])
 34 int N,M,T,TestCase,MaxVal;
 35 int root[MAXN],val[MAXN],h[MAXN],Tree_siz[MAXN],depth[MAXN];
 36 int fa[MAXN][25];
 37 Node *node[MAXN],*null;
 38 map <int,int> mp;
 39 vector <int> Edge[MAXN];
 40 ///==============function declaration============
 41 void Init();
 42 void Insert(Node *&o,int l,int r,int k);//向一个单点线段树中k的地方+1
 43 void Insert(Node *&prev,Node *&o,int l,int r,int k);//主席树k+1
 44 void Merge(int A);//将以A为根的树全部挂到A父亲上去
 45 //void Release(Node *&o);//释放空间,如果会超时就删掉
 46 int lca(int x,int y);//返回x和y的lca
 47 int Query(Node *&A1,Node *&A2,Node *&M1,Node *&M2,int l,int r,int rank);//查询A1和A2,M为LCA
 48 int findr(int x){return root[x] == x ? x : root[x] = findr(root[x]);}
 49 void update(Node *&o);
 50 ///==============main code=======================
 51 int main()
 52 {
 53 #ifndef ONLINE_JUDGE
 54     freopen("input","r",stdin);
 55     freopen("output","w",stdout);
 56 #endif
 57     null=new(Node);null->lc=null->rc=null;node[0]=null;
 58     Init();int lastans=0;
 59     while (T--){
 60         char cmd;
 61         do{
 62             scanf("%c",&cmd);
 63         }while (cmd!='L'&&cmd!='Q');
 64         if (cmd=='L'){
 65             int x,y;scanf("%d%d",&x,&y);x^=lastans;y^=lastans;
 66             int fx=findr(x),fy=findr(y);
 67             if (Tree_siz[fx]>Tree_siz[fy]){
 68                 swap(x,y);
 69                 swap(fx,fy);
 70             }
 71             Tree_siz[fy]+=Tree_siz[fx];root[fx]=fy;
 72             fa[x][0]=y;
 73             Edge[x].push_back(y);Edge[y].push_back(x);
 74             Merge(x);
 75         }
 76         else if (cmd=='Q'){
 77             int x,y,k;scanf("%d%d%d",&x,&y,&k);
 78             x^=lastans;y^=lastans;k^=lastans;
 79             int LCA=lca(x,y);
 80             lastans=Query(node[x],node[y],node[LCA],fa[LCA][0]==-1?null:node[fa[LCA][0]],1,MaxVal,k);
 81             lastans=h[lastans];
 82             printf("%d\n",lastans);
 83         }
 84     }
 85    return 0;
 86 }
 87 ///================fuction code====================
 88 void Init(){
 89     scanf("%d%d%d%d",&TestCase,&N,&M,&T);
 90     for(int i=1;i<=N;i++){//读入
 91         scanf("%d",val+i);;h[i]=val[i];
 92         root[i]=i;Tree_siz[i]=1;depth[i]=1;
 93         node[i]=new(Node);
 94     }
 95     memset(fa,-1,sizeof(fa));
 96     sort(h+1,h+1+N);
 97     MaxVal=unique(h+1,h+1+N)-h-1;
 98     for(int i=1;i<=MaxVal;i++)//离散化
 99         mp[h[i]]=i;
100     for(int i=1;i<=N;i++)
101         val[i]=mp[val[i]];
102     for(int i=1;i<=N;i++)//初始化节点
103         Insert(node[i],1,MaxVal,val[i]);
104     for(int i=1;i<=M;i++){//连边
105         int x,y;scanf("%d%d",&x,&y);
106         int fx=findr(x),fy=findr(y);
107         if (Tree_siz[fx]>Tree_siz[fy]){
108             swap(fx,fy);
109             swap(x,y);
110         }
111         Tree_siz[fy]+=Tree_siz[fx];
112         root[fx]=fy;//合并两棵树=。=
113             Edge[y].push_back(x);Edge[x].push_back(y);
114         fa[x][0]=y;
115         Merge(x);
116     }
117 }
118 void Merge(int A){//将以A为根的树全部重建
119     //Release(node[A]);
120     Insert(node[fa[A][0]==-1?0:fa[A][0]],node[A],1,MaxVal,val[A]);//将A建树=。=考虑要不要释放空间TAT
121     depth[A]=depth[fa[A][0]==-1?0:fa[A][0]]+1;
122     for(int i=1;(1<<i)<=N;i++){//更新lca信息
123         int rt=fa[A][i-1];
124         if (rt!=-1)
125             fa[A][i]=fa[rt][i-1];
126         else
127             fa[A][i]=-1;///就是这里!!!!!!!不然它还会是原来的父亲!!!!!
128     }
129     int siz=Edge[A].size();
130     for(int i=0;i<siz;i++){
131         int &e=Edge[A][i];
132         if (fa[A][0]!=e){
133             fa[e][0]=A;
134             Merge(e);
135         }
136     }
137 }
138 int lca(int x,int y){
139     if (depth[x]<depth[y]) swap(x,y);//x在下面TwT
140     int deltax=depth[x]-depth[y];
141     for(int i=0;(1<<i)<=deltax;i++)
142         if (deltax&(1<<i))
143             x=fa[x][i];
144     if (x==y) return x;
145     for(int i=20;i>=0;i--)
146         if (fa[x][i]!=fa[y][i]&&fa[x][i]!=-1&&fa[y][i]!=-1){
147             x=fa[x][i];
148             y=fa[y][i];
149         }
150     return fa[x][0];
151 }
152 int Query(Node *&A1,Node *&A2,Node *&M1,Node *&M2,int l,int r,int rank){
153     if (l==r) return l;
154     if (A1==NULL) A1=null;
155     if (A2==NULL) A2=null;
156     if (M1==NULL) M1=null;
157     if (M2==NULL) M2=null;
158     int ls=0;
159     if (M1->lc!=NULL) ls-=M1->lc->siz;
160     if (M2->lc!=NULL) ls-=M2->lc->siz;
161     if (A1->lc!=NULL) ls+=A1->lc->siz;
162     if (A2->lc!=NULL) ls+=A2->lc->siz;
163     int m=(l+r)>>1;
164     if (ls>=rank)
165         return Query(A1->lc,A2->lc,M1->lc,M2->lc,l,m,rank);
166     else
167         return Query(A1->rc,A2->rc,M1->rc,M2->rc,m+1,r,rank-ls);
168 }
169 void Insert(Node *&o,int l,int r,int k){
170     if (o==NULL) o=new(Node);
171     if (l==r){
172         o->siz++;
173         return;
174     }
175     int m=(l+r)>>1;
176     if (m>=k)
177         Insert(o->lc,l,m,k);
178     else
179         Insert(o->rc,m+1,r,k);
180     update(o);
181 }
182 void update(Node *&o){
183     if (o==NULL) return;
184     o->siz=0;
185     if (o->lc!=NULL)
186         o->siz+=o->lc->siz;
187     if (o->rc!=NULL)
188         o->siz+=o->rc->siz;
189 }
190 void Insert(Node *&prev,Node *&o,int l,int r,int k){
191     if (prev==NULL) prev=null;
192     if (o==NULL) o=new(Node);
193     int m=(l+r)>>1;
194     if (l==r){
195         o->siz=prev->siz+1;
196         return;
197     }
198     if (m>=k){
199         o->rc=prev->rc;
200         o->lc=new(Node);
201         Insert(prev->lc,o->lc,l,m,k);
202     }
203     else{
204         o->lc=prev->lc;
205         o->rc=new(Node);
206         Insert(prev->rc,o->rc,m+1,r,k);
207     }
208     update(o);
209 }
BZOJ 3123

  马上就要省选了我还是这么蒻肿么办啊!!好口啪!!

转载于:https://www.cnblogs.com/Houjikan/p/4425543.html

内容概要:本文系统介绍了基于C#(VS2022+.NET Core)与HALCON 24.11的工业视觉测量拟合技术,涵盖边缘提取、几何拟合、精度优化及工业部署全流程。文中详细解析了亚像素边缘提取、Tukey抗噪算法、SVD平面拟合等核心技术,并提供了汽车零件孔径测量、PCB焊点共面性检测等典型应用场景的完整代码示例。通过GPU加速、EtherCAT同步等优化策略,实现了±0.01mm级测量精度,满足ISO 1101标准。此外,文章还探讨了深度学习、量子启发式算法等前沿技术的应用前景。 适合人群:具备一定编程基础,尤其是熟悉C#和HALCON的工程师或研究人员,以及从事工业视觉测量与自动化检测领域的技术人员。 使用场景及目标:①学习如何使用C#和HALCON实现高精度工业视觉测量系统的开发;②掌握边缘提取、抗差拟合、3D点云处理等核心技术的具体实现方法;③了解工业部署中的关键技术,如GPU加速、EtherCAT同步控制、实时数据看板等;④探索基于深度学习和量子计算的前沿技术在工业视觉中的应用。 其他说明:本文不仅提供了详细的理论分析和技术实现,还附有完整的代码示例和实验数据,帮助读者更好地理解和实践。同时,文中提到的硬件选型、校准方法、精度验证等内容,为实际项目实施提供了重要参考。文章最后还给出了未来的技术演进方向和开发者行动建议,如量子-经典混合计算、自监督学习等,以及参与HALCON官方认证和开源社区的建议。
内容概要:本文介绍了基于WOA-GRU-Attention模型的时序数据分类预测项目,旨在提升时序数据分类准确率,实现智能优化,并提供强泛化能力的分类框架。项目背景指出传统机器学习方法难以处理时序数据的复杂特性,而GRU、注意力机制和WOA的结合能有效应对这些问题。文章详细描述了项目的目标与意义,包括提升分类准确率、实现智能优化、推动元启发式算法的应用等。同时,文中列出了项目面临的挑战及解决方案,如高维数据特征复杂、超参数调优难度大等。项目模型架构由WOA、GRU和注意力机制三部分组成,通过Python代码示例展示了模型的具体实现,包括模型定义、训练过程和WOA优化算法的核心步骤。; 适合人群:具备一定编程基础,尤其是对深度学习、时序数据分析感兴趣的开发者和研究人员。; 使用场景及目标:① 提升时序数据分类准确率,特别是在金融、医疗、智能制造等领域;② 实现模型训练过程的智能优化,避免传统调参的局限;③ 提供具备强泛化能力的时序数据分类框架,支持多行业多场景应用;④ 推动高性能时序模型的工业应用落地,提高智能系统的响应速度和决策质量。; 其他说明:项目不仅实现了工程应用,还在理论层面对GRU结构与注意力机制的融合进行了系统分析,结合WOA优化过程对模型训练动力学展开研究,促进了深度学习与优化算法交叉研究领域的发展。读者可以通过提供的代码示例和链接进一步了解项目的具体实现和应用场景。
内容概要:本文详细介绍了如何使用PyQt5创建一个功能全面的桌面备忘录应用程序,涵盖从环境准备、数据库设计、界面设计到主程序结构及高级功能实现的全过程。首先,介绍了所需安装的Python库,包括PyQt5、sqlite3等。接着,详细描述了SQLite数据库的设计,创建任务表和类别表,并插入默认类别。然后,使用Qt Designer设计UI界面,包括主窗口、任务列表、工具栏、过滤器和日历控件等。主程序结构部分,展示了如何初始化UI、加载数据库数据、显示任务列表以及连接信号与槽。任务管理功能方面,实现了添加、编辑、删除、标记完成等操作。高级功能包括类别管理、数据导入导出、优先级视觉标识、到期日提醒、状态管理和智能筛选等。最后,提供了应用启动与主函数的代码,并展望了扩展方向,如多用户支持、云同步、提醒通知等。 适合人群:零基础或初学者,对Python和桌面应用程序开发感兴趣的开发者。 使用场景及目标:①学习PyQt5的基本使用方法,包括界面设计、信号与槽机制;②掌握SQLite数据库的基本操作,如创建表、插入数据、查询等;③实现一个完整的桌面应用程序,具备增删改查和数据持久化功能;④了解如何为应用程序添加高级特性,如类别管理、数据导入导出、到期日提醒等。 阅读建议:此资源不仅适用于零基础的学习者,也适合有一定编程经验的开发者深入理解PyQt5的应用开发。建议读者跟随教程逐步实践,结合实际操作来理解和掌握每个步骤,同时可以尝试实现扩展功能,进一步提升自己的开发技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值