LOJ#510 北校门外的回忆(找性质+倍增+线段树)
这题一场模拟赛我们出了弱化版(n<=1e6),抄题面给的程序能拿到71分的好成绩
其实后面的29分是加了几个1e9的数据卡人
这糟老头子真是坏得很
正解我们机房看了三天
在这里感谢这篇题解的作者,代码解释得很清晰~
经过打表观察,可以发现:当\(1\le x \le k\)时
如果 \(k\) 为奇数,\(x*2^{y}\) \(mod\) \(k\)的值成环
如果 \(k\) 为偶数,质因数分解\(x\),如果所含因子\(2\)的次数大于\(k\)所含因子\(2\)的次数,那\(x*2^{y}\) \(mod\) \(k\)的值也成环
然而考试时永远发现不了
于是可以对每条链开一棵动态开点线段树,再开一棵线段树处理不在单点上的点,一起用来模拟题目所给的树状数组(\(N\le10^{9}\),直接开树状树组会炸)。
于是可以这么做修改操作:
对于不在链上的点,最多只会跳\(log_{2}^{k}*log_{k}^{n}=log_{2}^{n}\)次就会跳到\(n\)之外或跳到链上,暴力更新就完事了。
对于在链上的点,我们可以找到这条链的链头(找链头的方法详见代码),求出这个点到链头的距离\(dis\),区间更新\(dis\)和链尾之间的点。
查询也差不多的。
更详细的解释见代码:
#include <bits/stdc++.h>
#define N 200010
using namespace std;
int k;
inline void rd(int &x){
int y=0,f=1;char c=getchar();
while(c<'0' || c>'9' ){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9')y=y*10+(c^48),c=getchar();
x=y*f;
}
int num[N],jw[N],go[N][20],to[N][20],pr[N],a[N],fr,dis,u;
bool vis[N];
inline int lowbit(int x){
while(x%k==0) x/=k;
return x%k;
}
inline int lowbitv(int x){
register int lg=0;
while (x%k==0) x/=k,lg++;
x%=k;
while (lg) x*=k,lg--;
return x;
}
void init()//预处理
{
//jw[i]:i所在链上的进位次数
register int cnt,i,j,w,l;
for(i=1;i<=k;++i) for(j=i;j%2==0;j/=2,++pr[i]);
for(i=1;i<k;++i){
cnt=w=0;
if(vis[i] || pr[i]<pr[k]) continue;
int x=i*2%k;a[++cnt]=i,vis[i]=1;
while(x!=i) a[++cnt]=x,vis[x]=1,x=x*2%k;
for(j=1;j<=cnt;++j) w+=(a[j]*2>=k);
for(j=1;j<=cnt;++j){
jw[a[j]]=w,num[a[j]]=cnt;
(j==1)?x=cnt:x=j-1;
to[a[j]][0]=a[x];
go[a[j]][0]=(a[x]*2>=k);
}
//to[i][j]:i向前跳j步跳到的点
//go[i][j]:i向前跳j步的进位次数
for(j=1;j<=18;++j)
for(l=1;l<=cnt;++l){
to[a[l]][j]=to[to[a[l]][j-1] ][j-1];
go[a[l]][j]=go[a[l]][j-1]+go[to[a[l]][j-1] ][j-1];
}
}
}
void GetF(int x)//求链头
{
int lg=0;
while(x%k==0) x/=k,lg++;
fr=lowbit(x),dis=1;int u=(x-fr)/k,i;//u:x的进位次数
//dis=跳的环数*环的长度+剩余长度(没跳完整个环)
dis+=u/jw[fr]*num[fr];
u%=jw[fr];
for(i=18;i>=0;--i){
if(go[fr][i]<=u){
u-=go[fr][i];
dis+=(1<<i);
fr=to[fr][i];
}
}
while(lg) fr*=k,lg--;//由lowbit(x)的链头还原回去x的链头
}
#define mid ((l+r)>>1)
int root1,root2,root3;
struct tr{ int ls,rs,x; };
struct qwq{
tr t[N*60];
int sz=0;
void update(int &o,int l,int r,int L,int R,int v){
if(!o) o=++sz;
if(L<=l && r<=R){
t[o].x^=v;
return;
}
if(L<=mid) update(t[o].ls,l,mid,L,R,v);
if(R>mid) update(t[o].rs,mid+1,r,L,R,v);
}
int query(int o,int l,int r,int x){
if(l==r || !o) return t[o].x;
if(x<=mid) return t[o].x^query(t[o].ls,l,mid,x);//不用pushup的原因(异或只用异或一遍)
else return t[o].x^query(t[o].rs,mid+1,r,x);
}
} Point,Chain,Front;
//Point:不在链上的点
//Chain:链上的点的更新(以链头的点值为根)
//Front:链头在Chain上的位置
int main()
{
int n,q,op,x,v,ans;
rd(n),rd(q),rd(k);
init();
while(q--){
rd(op),rd(x);
if(op==1){
rd(v);
while(x<=n && pr[lowbit(x)]<pr[k]){
Point.update(root2,1,n,x,x,v);
x+=lowbitv(x);
} //暴力跳
if(x>n) continue;
GetF(x);
root1=Front.query(root3,1,n,fr);
int tmp=root1;Chain.update(root1,1,n,dis,n,v);
//Chain相当于重构了编号,比如说链头为x,则线段树里编号为2的元素实际上是原树状数组编号为x+lowbit(x)的元素
if(!tmp) Front.update(root3,1,n,fr,fr,root1);
} else{
ans=0;
while(x){
if(pr[lowbit(x)]<pr[k]) ans^=Point.query(root2,1,n,x);
else{
GetF(x);
root1=Front.query(root3,1,n,fr);
if(root1) ans^=Chain.query(root1,1,n,dis);
}
x-=lowbitv(x);
}
printf("%d\n",ans);
}
}
}
LOJ#510 北校门外的回忆(找性质+倍增+线段树)的更多相关文章
- LOJ 510: 「LibreOJ NOI Round #1」北校门外的回忆
题目传送门:LOJ #510. 题意简述: 给出一个在 \(K\) 进制下的树状数组,但是它的实现有问题. 形式化地说,令 \(\mathrm{lowbit}(x)\) 为在 \(K\) 进制下的 \ ...
- LOJ #2359. 「NOIP2016」天天爱跑步(倍增+线段树合并)
题意 LOJ #2359. 「NOIP2016」天天爱跑步 题解 考虑把一个玩家的路径 \((x, y)\) 拆成两条,一条是 \(x\) 到 \(lca\) ( \(x, y\) 最近公共祖先) 的 ...
- LOJ#510. 「LibreOJ NOI Round #1」北校门外的回忆(线段树)
题面 传送门 题解 感谢\(@M\_sea\)的代码我总算看懂题解了-- 这个操作的本质就是每次把\(x\)的\(k\)进制最低位乘\(2\)并进位,根据基本同余芝士如果\(k\)是奇数那么最低位永远 ...
- LOJ 北校门外的回忆 倍增+线段树
正解:倍增+线段树 解题报告: 传送门! $umm$这题有个对正解毫无启发的部分分还有个正解,都挺神仙的所以我都写了趴$QAQ$ 先说部分分 可以考虑把$x$向$x+lowbit(x)$连边,然后当$ ...
- 51nod 1463 找朋友 (扫描线+线段树)
1463 找朋友 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 难度:5级算法题 收藏 关注 给定: 两个长度为n的数列A .B 一个有m个元素的集合K 询问Q次 每次询 ...
- 【NOI P模拟赛】校门外歪脖树上的鸽子(树链剖分)
题面 2 ≤ n ≤ 2 × 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ l ≤ r ≤ n , 1 ≤ d ≤ 1 0 8 2 ≤ n ≤ 2 × 10^5,1 ≤ m ≤ 2 ...
- loj#6029. 「雅礼集训 2017 Day1」市场(线段树)
题意 链接 Sol 势能分析. 除法是不能打标记的,所以只能暴力递归.这里我们加一个剪枝:如果区间内最大最小值的改变量都相同的话,就变成区间减. 这样复杂度是\((n + mlogn) logV\)的 ...
- LOJ.6062.[2017山东一轮集训]Pair(Hall定理 线段树)
题目链接 首先Bi之间的大小关系没用,先对它排序,假设从小到大排 那么每个Ai所能匹配的Bi就是一个B[]的后缀 把一个B[]后缀的匹配看做一条边的覆盖,设Xi为Bi被覆盖的次数 容易想到 对于每个i ...
- 51nod 1463 找朋友(线段树+离线处理)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1463 题意: 思路: 好题! 先对所有查询进行离线处理,按照右区间排序, ...
随机推荐
- bootstrap 弹窗或者提示框插件 bootstrap-growl 和bootstrap-notify
Bootstrap简单好用的页面右上角咆哮提示框 - daidaineteasy的专栏 - CSDN博客https://blog.csdn.net/daidaineteasy/article/deta ...
- js文字从左边飞入效果
贴代码之前,我们先讲一下它的原理,我们使用setInterval,让文字一开始置于屏幕看不到的位置,左右上下都可以,然后让它的位置不断移入到屏幕看得到的位置. 下面上代码: html: <h2 ...
- 配置router列表
import Vue from "vue"; import VueRouter from 'vue-router'; import Star from '../components ...
- Laravel中resource方法
新增的 resource 方法将遵从 RESTful 架构为用户资源生成路由.该方法接收两个参数,第一个参数为资源名称,第二个参数为控制器名称. Route::resource('users', 'U ...
- hihoCoder1033 交错和 数位DP
题目:交错和 链接:http://hihocoder.com/problemset/problem/1033# 题意:对于一个十进制整数x,令a0.a1.a2.....an是x从高位到低位的数位,定义 ...
- Mybatis 配置resultMap一对多关联映射
resultMap配置: 引用: PO类: 接口: 测试: public class UserMapperTest { private SqlSessionFactory sqlSessionFact ...
- npm的nrm命令使用--设置镜像地址
npm下载会很慢,因为npm默认从国外下载资源,建议修改npm镜像源地址 1.运行npm i nrm -g全局安装nrm包: 2.使用nrm ls查看当前所有可用的镜像源地址以及当前所使用的镜像源地址 ...
- Java8 Stream实例--统计出所有含‘张’字的人员的平均年龄
package com.zhangxueliang.demo; import java.util.ArrayList; import java.util.List; import java.util. ...
- 动态SQL2
set标签 存放修改方法,我们之前写的更新方法是全字段的更新,或者是指定字段的更新,现在我想实现一个新功能,传入的Employee包含什么字段,数据库就更新相对应的列值: 如果我们啥也不做直接上< ...
- python学习笔记(11)--数据组织的维度
数据的操作周期 存储 -- 表示 -- 操作 一维数据表示 如果数据有序,可以使用列表[]:如果数据没有顺序,可以使用集合{} 一维数组存储 存储方式一:空格分隔 ,使用一个或多个空格分隔进行分隔, ...