ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Loj#510-「LibreOJ NOI Round #1」北校门外的回忆【线段树】

2022-07-14 12:04:07  阅读:125  来源: 互联网

标签:return pw 北校 Loj mid int ans id NOI


正题

题目链接:https://loj.ac/p/510


题目大意

给出一个代码

function add(x,v)
    while x <= n do
        s[x] = s[x] xor v
        x = x + lowbit(x) //注意,这里是 lowbit,这也是两份代码唯一的区别
    end while
end function

function query(x)
    ans = 0
    while x > 0 do
        ans = ans xor s[x]
        x = x - lowbit(x)
    end while
    return ans
end function

其中\(\text{lowbit(x)}\)表示\(x\)在\(K\)进制下最低非零位的值。

现在给出\(n,q,K\),\(q\)次调用\(add(x,v)\)或者\(query(x)\)。

要求输出每次\(query(x)\)调用的值。

\(1\leq n\leq 10^9,2\leq q,K\leq 2\times 10^5\)


解题思路

注意到询问的时候我们是可以一位一位的做的,主要是修改的时候。

我们先默认最低非零位就是个位,那么相当于每次\(x=x+x\% K\)直到\(x|K\),如果只考虑个位的情况,也可以视为每次\(x=2x\% K\)。

首先每个数只有两种到达它的情况,一个是\(\frac{x}{2}\),另一个是\(\frac{x+K}{2}\),那么如果\(K\)是奇数的话,这两个中恰好有一个是整数,也就是每个数字的入边都是\(1\),出边也是\(1\),所以最终图肯定会形成若干个环。

那么考虑\(K\)不是奇数的情况,如果\(x\)的\(2\)质因子个数不少于\(K\)的,那么它们则可以表示为\(\frac{x}{2^p}\)和\(\frac{K}{2^p}\),这样的话\(K\)又是奇数了,也会构成环。

否则\(x\)一直乘二直到质因子个数不少于\(K\),也就是说这种情况走不超过\(\log K\)步就一定能到达一个环或者\(0\)。

那么我们就是先分位计算,最低位不在环上就暴力跳,在环上就考虑维护。

现在主要是环上怎么维护的问题,同一个最低位上,对于一个修改\(xy\)(个位是\(y\),剩下的位是\(x\)),会影响一个询问\(x'y'\)的条件。

我们需要找到一个不关于这些点的个位的条件,那么我们就考虑对于每个环定义一个点作为环头,然后所有的操作询问都移动到环头上搞。

然后我们把每个修改拆成修改位置到环头一段和从环头开始不停绕环的一段,

那么第一个的一个限制是询问位置要在它后面并且它们都反着退到环头后值相等,可以用线段树维护位置关系。

第二个先把询问倒着移动到环头,那么限制就是它们对于环上进位次数和的余数相等并且询问的值大于修改的值,可以用权值线段树维护。

时间复杂度:\(O(K\log^2 n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=2e5+10,M=N<<7;
int n,q,K,cnt,lg[N],id[N],sum[N],noe[N],dis[N],len[N];
map<pair<int,int> ,int>rt[40],Rt[40];
map<int,int> g;
struct SegTree{
	int cnt,w[M],ls[M],rs[M];
	void Change(int &x,int L,int R,int pos,int val){
		if(pos<L||pos>R)return;
		if(!x)x=++cnt;w[x]^=val;
		if(L==R)return;int mid=(L+R)>>1;
		if(pos<=mid)Change(ls[x],L,mid,pos,val);
		else Change(rs[x],mid+1,R,pos,val);
		return;
	}
	int Ask(int x,int L,int R,int l,int r){
		r=min(r,R);l=max(l,L);
		if(l>r||!w[x])return 0;
		if(L==l&&R==r)return w[x];
		int mid=(L+R)>>1;
		if(r<=mid)return Ask(ls[x],L,mid,l,r);
		if(l>mid)return Ask(rs[x],mid+1,R,l,r);
		return Ask(ls[x],L,mid,l,mid)^Ask(rs[x],mid+1,R,mid+1,r);
	}
}T;
void dfs(int x,int pos,int one,int fr){
	if(id[x]){sum[fr]=one;return;}
	noe[x]=one;id[x]=fr;dis[x]=pos;len[fr]++;
	dfs(x*2%K,pos+1,one+(x*2>=K),fr);
	return;
}
int main()
{
	scanf("%d%d%d",&n,&q,&K);
	for(int i=1;i<=K;i++)
		if(i%2==0)lg[i]=lg[i/2]+1;
	for(int i=1;i<K;i++)
		if(lg[i]>=lg[K]&&!id[i])
			++cnt,dfs(i,0,0,cnt);
	while(q--){
		int op;scanf("%d",&op);
		if(op==1){
			int x,w,i=0,pw=1;
			scanf("%d%d",&x,&w);
			while(x*pw<=n){
				int p=x%K,y=x/K;
				while(p&&x*pw<=n){
					if(lg[p]>=lg[K]){
						T.Change(rt[i][mp(id[p],y-noe[p])],0,len[id[p]]-1,dis[p],w);
						T.Change(Rt[i][mp(id[p],(y-noe[p]+sum[id[p]])%sum[id[p]])],0,n/pw/K,y+sum[id[p]]-noe[p],w);
						x=0;break;
					}
					else g[x*pw]^=w,x+=x%K,p=x%K,y=x/K;
				}
				if(!x||x*pw>n)break;
				x=x/K;pw=pw*K;i++;
			}
		}
		else{
			int x;scanf("%d",&x);
			int i=0,pw=1,ans=0;
			while(x){
				int p=x%K,y=x/K;
				if(p!=0){
					if(lg[p]>=lg[K]){
						ans^=T.Ask(rt[i][mp(id[p],y-noe[p])],0,len[id[p]]-1,0,dis[p]);
						ans^=T.Ask(Rt[i][mp(id[p],(y-noe[p]+sum[id[p]])%sum[id[p]])],0,n/pw/K,0,y-noe[p]);
					}
					else ans^=g[x*pw];
				}
				x/=K;i++;pw=pw*K;
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}

标签:return,pw,北校,Loj,mid,int,ans,id,NOI
来源: https://www.cnblogs.com/QuantAsk/p/16477179.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有