A.不相邻集合

考虑值域上连续的段,可以发现连续的长度为 \(x\) 的段的贡献必定为 \(\lceil{\frac{x}{2}}\rceil\)

考虑并查集维护值域连续的段的大小,每次询问求出全部连续段的 \(\lceil{\frac{size}{2}}\rceil\) 之和即为答案

合并操作:在值域上加入 \(x\),尝试合并 \(x-1\) 与 \(x+1\)

复杂度不对,考虑优化

  1. 记一个关于值域的 \(vis\),若单次插入不改变 \(vis\),则答案不变
  2. 每次在并查集上合并时直接统计答案,先减去两个分别的答案,再加上总和的答案
  3. 记得新加入单点时的贡献为 \(\lceil{\frac{1}{2}}\rceil=1\)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define void inline void
// #define ONLINE_JUDGE
#ifndef ONLINE_JUDGE
#define test(i) cout<<"test: "<<i<<endl
#define testp(i,j) cout<<i<<" "<<j<<endl
#define testd(i) cout<<i<<" "
#define end cout<<"\n"
#define div <<" "<<
#else
#define test(i)
#define testp(i,j)
#define testd(i)
#define end false
#define div ,
#endif
template<typename T>
void read(T& x){
x=0;bool sym=0;char c=getchar();
while(!isdigit(c)){sym^=(c=='-');c=getchar();}
while(isdigit(c)){x=x*10+c-48;c=getchar();}
if(sym)x=-x;
}
template<typename T,typename... Args>
void read(T& x,Args&... args){
read(x);read(args...);
}
vector<int>has;
int ans=0;
class dsu{
public:
int fa[500001],siz[500001];
void reset(int n){
for(int i=1;i<=n;++i){
fa[i]=i;
siz[i]=1;
}
}
int find(int id){
if(fa[id]==id) return id;
fa[id]=find(fa[id]);
return fa[id];
}
void connect(int x,int y){
int fx=find(x),fy=find(y);
if(fx!=fy){
fa[fx]=fy;
ans-=(siz[fy]+1)/2+(siz[fx]+1)/2;
siz[fy]+=siz[fx];
ans+=(siz[fy]+1)/2;
}
}
};
dsu d;
int a[300001];
bool vis[500001];
int tot,lastans=0;
int main(){
int n;
read(n);d.reset(500000);
for(int i=1;i<=n;++i){
read(a[i]);
if(!vis[a[i]]){
vis[a[i]]=true;
has.push_back(a[i]);
ans++;
if(vis[a[i]-1]){
d.connect(a[i],a[i]-1);
}
if(vis[a[i]+1]){
d.connect(a[i],a[i]+1);
}
}
cout<<ans<<' ';
}
}

B.线段树

设 \(f(n,x)\) 表示对从长度为 \(n\) 的连续段建立线段树(即有 \(n\) 个叶节点),根节点的值为 \(x\),左儿子的值为 \(2x\),右儿子的值为 \(2x+1\) 的情况下的全部节点权值和

可以发现对于根节点儿子的权值,相对于根节点权值的变化只有两种:即乘以一个系数或者加上若干值,也即 \(f(n,x)\) 是关于 \(x\) 的一次函数

设 \(f(n,x)=k_{n}x+b_{n}\),考虑到我们在对此线段树向下分治的时候,总会有 \(\lceil{\frac{n}{2}}\rceil\) 长度的区间被分配到左儿子,\(\lfloor{\frac{n}{2}}\rfloor\) 长度的区间被分配到右儿子,也就是说:

\[f(n,x)=f(\lceil{\frac{n}{2}}\rceil,2x)+f(\lfloor{\frac{n}{2}}\rfloor,2x+1)+x
\]

根据上设,可得

\[k_{n}x+b_{n}=k_{\lceil{\frac{n}{2}}\rceil}2x+b_{\lceil{\frac{n}{2}}\rceil}+k_{\lfloor{\frac{n}{2}}\rfloor}(2x+1)+b_{\lfloor{\frac{n}{2}}\rfloor}+x
\]

解这个方程,得到

\[\begin{cases}k_{n}=2k_{\lceil{\frac{n}{2}}\rceil}+2k_{\lfloor{\frac{n}{2}}\rfloor}+1\\b_{n}=b_{\lceil{\frac{n}{2}}\rceil}+k_{\lfloor{\frac{n}{2}}\rfloor}+b_{\lfloor{\frac{n}{2}}\rfloor}\end{cases}
\]

关于这个递推式的初态,可以感性理解

  • 当 \(n=1\) 时,线段树中只有一个节点 \(x\),因此 \(k_{1}=1,b_{1}=0\)
  • 当 \(n=2\) 时,线段树中只有三个节点 \(x,2x,2x+1\),和为 \(5x+1\),因此 \(k_{1}=5,b_{1}=1\)

其余开 map 记搜即可

如果你们 WA60 也有可能是 build() 里的 id 忘记取模了

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
template<typename T>
inline T read(){
T x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch-'0');
ch=getchar();
}
return x*f;
}
template<typename T>
inline T read(T&a){
T x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch-'0');
ch=getchar();
}
return a=x*f;
}
template<typename T>
inline void write(T x){
if(x<0)x*=-1,putchar('-');
if(x>9)write(x/10);
putchar(x%10+'0');
return;
}
const int p=1e9+7;
map<int,int> K,B;
int k(int n){
if(n==0) return 0;
if(n==1) return 1;
if(n==2) return 5;
if(K.count(n)) return K[n];
return K[n]=(2*(k((n+1)/2)+k(n/2))+1)%p;
}
int b(int n){
if(n==0) return 0;
if(n==1) return 0;
if(n==2) return 1;
if(B.count(n)) return B[n];
return B[n]=(b((n+1)/2)+b(n/2)+k(n/2))%p;
}
int build(int id,int l,int r,int L,int R){
if(l>R or r<L) return 0;
if(L<=l and r<=R){
return (k(r-l+1)*id%p+b(r-l+1))%p;
}
int mid=(l+r)/2;
return (build((id*2)%p,l,mid,L,R)+build((id*2+1)%p,mid+1,r,L,R))%p;
}
signed main(){
int T;read(T);
while(T--){
int n,l,r;
read(n);read(l);read(r);
write(build(1,1,n,l,r)%p);putchar('\n');
}
}

C.魔法师

题目需要我们求 \(\max(a_{i}+a_{j},b_{i}+b_{j})\)

分类讨论,注意到 \(a_{i}+a_{j}\gt b_{i}+b_{j}\) 的时候,只需要令 \(a_{i}-b_{i}\gt b_{j}-a_{j}\) 即可,此时的答案即为 \(a_{i}+a_{j}\),否则,当 \(a_{i}-b_{i}\le b_{j}-a_{j}\) 时,答案便为 \(b_{i}+b_{j}\),这样我们就去除了 \(\max\) 符号

因此我们尝试对每个 \(u_{i}=a_{i}-b_{i},v_{i}=b_{i}-a_{i}\) 进行比较. 现在我们可以把问题转化为求满足 \(u_{i}\gt v_{j}\) 的 \((i,j)\) 的 \(a_{i}+a_{j}\) 最小值,或者满足 \(u_{i}\le v_{j}\) 的 \((i,j)\) 的 \(b_{i}+b_{j}\) 最小值,在两者中再取一个最小值即为答案.

考虑对 \(u,v\) 建一颗权值线段树,考虑到,当 \(i\) 在左子树,\(j\) 在右子树时,一定有 \(u_{i}\le v_{j}\),因此 \((i,j)\) 可以用于更新父亲节点 \(b_{i}+b_{j}\) 的最小值,反之同理,而我们需要的整体最小值,要么就是从子节点继承上来的答案,要么就是该节点的 \(i\) 在左子树,\(j\) 在右子树时的情况或者 \(j\) 在左子树,\(i\) 在右子树时贡献的情况,可以发现这样做正好覆盖了全部合法的 \((i,j)\)

因为在 \((i,j)\) 中,一定有前者为法杖,后者为咒语。因此在增加操作中,遇到法杖 \(i\) 则在 \(a-b\) 位置插入节点 \((a_{i},b_{i})\),遇到咒语 \(j\) 则在 \(b-a\) 位置插入节点 \((a_{j},b_{j})\),然后按顺序向上更新每层法杖的 \(a,b\) 最小值,咒语的 \(a,b\) 最小值,然后在当前节点用左子树法杖,右子树咒语,或者左子树咒语,右子树法杖的最小值分别计算贡献并取最小值即可

关于删除操作,注意到同一个叶节点下方可能会有多个 \((a,b)\),因此考虑建树套树,简化一点开个 set 维护,因为我们需要分别统计四个最值,因此对每个叶节点开四个 set,分别以不同关键字排序,统计答案的时候取首位维护最小值,删除的时候直接暴力搜索删除,记得删除之后要将该节点统计信息清空后重新统计一遍,防止原先较大的答案未被覆盖导致的错误.

处于空间考虑,我们只需要对每个叶节点开一个 set,因此考虑将 set 建在外面,线段树里面只存储 set 的编号来处理. 由于 \(a-b\) 可能存在负数,因此需要整体偏移,鉴于 \(a,b\in[0,2.5e5]\),偏移量为 \(0-2.5e5=-2.5e5\),线段树范围为 \(2.5e5-0-(-2.5e5)=5e5\),最大值不超过 \(2.5e5+2.5e5=5e5\),不用开 long long

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
template<typename T>
void read(T& x){
x=0;bool sym=0;char c=getchar();
while(!isdigit(c)){sym^=(c=='-');c=getchar();}
while(isdigit(c)){x=x*10+c-48;c=getchar();}
if(sym)x=-x;
}
template<typename T,typename... Args>
void read(T& x,Args&... args){
read(x);read(args...);
}
#define tests int cases;read(cases);while(cases--)
#define pb push_back
int Q,T;
const int N=5e5+10,dx=N/2;
const int inf=1e8;
int lastans=0;
struct node{
int a,b;
bool operator <(const node &A)const{
if(a==A.a) return b<A.b;
return a<A.a;
}
};
struct node2{
int a,b;
bool operator <(const node2 &A)const{
if(b==A.b) return a<A.a;
return b<A.b;
}
};
struct setpair{
set<node> pa,qa;
set<node2> pb,qb;
};
vector<setpair>store;
namespace Stree{
#define tol (id*2)
#define tor (id*2+1)
#define mid(l,r) mid=(l+r)/2
struct tree{
int l,r;
int store_id;
int minap,minaq,minbp,minbq;
int minansa,minansb;
}t[4*N];
void pushup(int id){
t[id].minap=inf;
t[id].minaq=inf;
t[id].minbp=inf;
t[id].minbq=inf;
t[id].minansa=t[id].minansb=inf;
if(t[tol].l){
t[id].minap=min(t[tol].minap,t[id].minap);
t[id].minaq=min(t[tol].minaq,t[id].minaq);
t[id].minbp=min(t[tol].minbp,t[id].minbp);
t[id].minbq=min(t[tol].minbq,t[id].minbq);
t[id].minansa=min(t[tol].minansa,t[id].minansa);
t[id].minansb=min(t[tol].minansb,t[id].minansb);
}
if(t[tor].l){
t[id].minap=min(t[tor].minap,t[id].minap);
t[id].minaq=min(t[tor].minaq,t[id].minaq);
t[id].minbp=min(t[tor].minbp,t[id].minbp);
t[id].minbq=min(t[tor].minbq,t[id].minbq);
t[id].minansa=min(t[tor].minansa,t[id].minansa);
t[id].minansb=min(t[tor].minansb,t[id].minansb);
}
if(t[tol].l and t[tor].l){
t[id].minansa=min({t[tol].minansa,t[tor].minansa,t[tol].minaq+t[tor].minap});
t[id].minansb=min({t[tol].minansb,t[tor].minansb,t[tol].minbp+t[tor].minbq});
}
}
void build(int id,int l,int r){
t[id].l=l;t[id].r=r;
t[id].minap=inf,t[id].minaq=inf;
t[id].minbp=inf,t[id].minbq=inf;
t[id].minansa=inf;t[id].minansb=inf;
if(l==r){
store.push_back({});
t[id].store_id=(int)store.size()-1;
return;
}
int mid(l,r);
build(tol,l,mid);
build(tor,mid+1,r);
}
void update(int id,bool isp){
if(!store[t[id].store_id].pa.empty()) t[id].minap=store[t[id].store_id].pa.begin()->a;
else t[id].minap=inf;
if(!store[t[id].store_id].pb.empty()) t[id].minbp=store[t[id].store_id].pb.begin()->b;
else t[id].minbp=inf;
if(!store[t[id].store_id].qa.empty()) t[id].minaq=store[t[id].store_id].qa.begin()->a;
else t[id].minaq=inf;
if(!store[t[id].store_id].qb.empty()) t[id].minbq=store[t[id].store_id].qb.begin()->b;
else t[id].minbq=inf;
t[id].minansa=min(inf,t[id].minap+t[id].minaq);
t[id].minansb=min(inf,t[id].minbp+t[id].minbq);
}
void update2(int id,bool isp,int a,int b){
if(isp){
t[id].minap=min(t[id].minap,a);
t[id].minbp=min(t[id].minbp,b);
}
else{
t[id].minaq=min(t[id].minaq,a);
t[id].minbq=min(t[id].minbq,b);
}
t[id].minansa=min(inf,t[id].minap+t[id].minaq);
t[id].minansb=min(inf,t[id].minbp+t[id].minbq);
}
void change(int id,int pos,bool isp,int a,int b){
if(t[id].l==t[id].r){
if(isp){
store[t[id].store_id].pa.insert({a,b});
store[t[id].store_id].pb.insert({a,b});
}
else{
store[t[id].store_id].qa.insert({a,b});
store[t[id].store_id].qb.insert({a,b});
}
update2(id,isp,a,b);
return;
}
if(pos<=t[tol].r) change(tol,pos,isp,a,b);
else change(tor,pos,isp,a,b);
pushup(id);
}
void remove(int id,int pos,int isp,int a,int b){
if(t[id].l==t[id].r){
if(isp){
auto it1=store[t[id].store_id].pa.lower_bound(node{a,b});
auto it2=store[t[id].store_id].pb.lower_bound(node2{a,b});
if(it1!=store[t[id].store_id].pa.end() and it1->a==a and it1->b==b){
store[t[id].store_id].pa.erase(it1);
store[t[id].store_id].pb.erase(it2);
}
}
else{
auto it1=store[t[id].store_id].qa.lower_bound(node{a,b});
auto it2=store[t[id].store_id].qb.lower_bound(node2{a,b});
if(it1!=store[t[id].store_id].qa.end() and it1->a==a and it1->b==b){
store[t[id].store_id].qa.erase(it1);
store[t[id].store_id].qb.erase(it2);
}
}
update(id,isp);
return;
}
if(pos<=t[tol].r) remove(tol,pos,isp,a,b);
else remove(tor,pos,isp,a,b);
pushup(id);
}
int solve(){
return min(t[1].minansa,t[1].minansb);
}
}
using namespace Stree;
signed main(){
read(Q,T);
build(1,1,N);
for(int i=1;i<=Q;++i){
int op,t,a,b;read(op,t,a,b);
if(T==1){
a^=lastans;b^=lastans;
}
if(op==1){
if(t==0){
change(1,a-b+dx,true,a,b);
}
else{
change(1,b-a+dx,false,a,b);
}
}
else{
if(t==0){
remove(1,a-b+dx,true,a,b);
}
else{
remove(1,b-a+dx,false,a,b);
}
}
int res=solve();
cout<<(lastans=(res==inf?0:res))<<endl;
}
}

[29] CSP模拟2的更多相关文章

  1. Nescafe #29 NOIP模拟赛

    Nescafe #29 NOIP模拟赛 不知道这种题发出来算不算侵权...毕竟有的题在$bz$上是权限题,但是在$vijos$似乎又有原题...如果这算是侵权的话请联系我,我会尽快删除,谢谢~ 今天开 ...

  2. csp模拟赛低级错误及反思

    \(csp\)模拟赛低级错误及反思. 1.没开\(longlong\). 反思:注意数据类型以及数据范围. 2.数组越界(前向星数组未开两倍,一题的数据范围应用到另一题上,要开两倍的写法为开两倍数组) ...

  3. 2018.06.29 NOIP模拟 Gcd(容斥原理)

    Gcd 题目背景 SOURCE:NOIP2015-SHY-2 题目描述 给出n个正整数,放入数组 a 里. 问有多少组方案,使得我从 n 个数里取出一个子集,这个子集的 gcd 不为 1 ,然后我再从 ...

  4. 9.27下午考试(Nescafé 29杯模拟赛)

    140pts(100+30+10)Rank3 前几天还考了一场,AK,没什么好总结的,所以就没写博客. 炸: T2,模拟退火突然不会了,写个状压dp,排序边的时候sort的N而不是M. 这个坑经常出! ...

  5. 19.7.29 NOIP模拟10

    话说这次三道考试题直接可以连成一个段子:我一个辣鸡,连模板都不会打,只能跪倒在大佬面前; T1 辣鸡 但是我实在是太辣鸡了,最后干的T1,时间不够用,连暴力都没打对,无奈之下交了一个qj程序,60分( ...

  6. 【CSP模拟赛】Freda的迷宫(桥)

    题目描述 Freda是一个迷宫爱好者,她利用业余时间建造了许多迷宫.每个迷宫都是由若干房间和走廊构成的,每条走廊都连接着两个不同的房间,两个房间之间最多只有一条走廊直接相连,走廊都是双向通过.  黄昏 ...

  7. 【csp模拟赛九】--dfs3

    这道题贪心错误:直接dfs就行,枚举新开一个还是往之前的里面塞 贪心代码(80): #include<cstdio> #include<algorithm> #include& ...

  8. 2019.7.29 NOIP模拟测试10 反思总结【T2补全】

    这次意外考得不错…但是并没有太多厉害的地方,因为我只是打满了暴力[还没去推T3] 第一题折腾了一个小时,看了看时间先去写第二题了.第二题尝试了半天还是只写了三十分的暴力,然后看到第三题是期望,本能排斥 ...

  9. @CSP模拟2019.10.16 - T3@ 垃圾分类

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 为了保护环境,p6pou建设了一个垃圾分类器. 垃圾分类器是一个 ...

  10. CSP模拟赛2游记

    这次由于有课迟到30min,了所以只考了70min. 调linux配置调了5min,只剩下65min了. T1:有点像标题统计,但要比他坑一点,而且我就被坑了,写了一个for(int i=1;i< ...

随机推荐

  1. MySQL 实现 EF Code First TimeStamp/RowVersion 并发控制

    在将项目迁移到MySQL 5.6.10数据库上时,遇到和迁移到PostgreSQL数据库相同的一个问题,就是TimeStamp/RowVersion并发控制类型在非Microsoft SQL Serv ...

  2. STM32开发环境配置记录——关于PlatformIO + VSCode + CubeMX的集成环境配置

    前言 ​ 为什么配置这样的一个环境呢?鄙人受够了Keil5那个简陋的工作环境了,实在是用不下去,调试上很容易跟CubeMX的代码产生不协调导致调试--发布代码不一致造成的一系列问题.CubeIDE虽说 ...

  3. ios的idp/iep证书的生成方法,无苹果电脑

    在这个多端开发的年代,出现了很多优秀的开发框架,比如hbuilder和uniapp等等.我们可以使用这些框架来开发APP,假如我们要打包ios的app,则需要一个idp/iep证书. 那么这个证书是如 ...

  4. web3 产品介绍: safe --多签钱包 多人审批更放心

    Safe是一款由Gnosis团队开发的多签钱包,它提供了一种安全.灵活和易于使用的方式来管理加密资产.在本文中,我们将介绍Safe的主要特点以及如何使用Safe来保护您的数字资产. 一.Safe的特点 ...

  5. 【DataBase】MySQL 27 函数

    一.概述 函数 Function,存储过程的用途一致,减少程序逻辑,和数据库服务的连接次数,提高效率 简化操作,提高SQL重用性 函数 和 存储过程的区别? 存储过程允许多个返回的数据,函数只允许一个 ...

  6. 【Mybatis】12 复杂关联查询

    一对多 & 多对一 关联查询 数据库准备: 一个班级表,字段:班级ID + 班级名称 一个学生表,字段:学生ID + 学生姓名 + 所属的班级ID # 班级表 班级ID+班级名称 CREATE ...

  7. 【Vue】Re05 操作数组的API

    一.响应式处理的操作: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  8. 美国小伙: "American Guy: Only communism can save America!"

    视频地址: https://www.youtube.com/watch?v=Y_WQnXFh8ss 2024大选在即,又是拜登对阵特朗普的旧日重现.在角逐谁的对手反对者更多的畸形内耗中,有一个名为 M ...

  9. 如何使用Python环境下的2D经典游戏仿真器(openai推出的)retro库运行游戏"刺猬索尼克" (SonicTheHedgehog-Genesis)

    很多资料上都有使用游戏仿真器(openai推出的)retro库运行游戏"刺猬索尼克"  (SonicTheHedgehog-Genesis),但是均没有给出详细的安装该款游戏的步骤 ...

  10. windows10开启电源模式中的休眠选项

    使用管理员权限开启PowerShell,输入命令: powercfg -h on