LOJ #510. 「LibreOJ NOI Round #1」北校門外的回憶(倍增+動態開點線段樹)

題目

這個題是一個精彩的分析性質區間離散的問題

真的詳細

維護鏈真的一絕。

LOJ\rm LOJ最短AC Code\rm AC \ Code

#include<bits/stdc++.h>
#define maxn 200005
#define lim 30
using namespace std;

int n,q,K,f[lim][maxn];
map<int,int>t1,rt;
int Find(int x){
	int r=x%K;x/=K;for(;~r&1;r>>=1);
	for(int i=lim-1;i>=0;i--) if(x>>i&1) r=f[i][r];
	return r;
}
int sum[maxn*lim],lc[maxn*lim],rc[maxn*lim],cnt;
void Add(int &u,int l,int r,int p,int v){
	if(!u)u=++cnt;sum[u] ^= v;
	if(l==r) return;
	int mid=(l+r)>>1;p<=mid?Add(lc[u],l,mid,p,v):Add(rc[u],mid+1,r,p,v);
}
int Query(int u,int l,int r,int p){
	if(!u || l==r) return sum[u];
	int mid = (l+r)>>1;
	return p<=mid?Query(lc[u],l,mid,p):(sum[lc[u]]^Query(rc[u],mid+1,r,p));
}

int main(){
	scanf("%d%d%d",&n,&q,&K);
	int t = K , lB = (K&-K)-1;
	for(;~t&1;t>>=1);
	for(int i=1;i<t;i+=2){
		int v=i+t;for(;~v&1;v>>=1);
		f[0][i]=v;
	}
	for(int j=1;j<lim;j++) for(int i=1;i<=t;i+=2) f[j][i] = f[j-1][f[j-1][i]];
	for(int op,x,v;q--;){
		scanf("%d%d",&op,&x);
		for(t=1;x%K==0;x/=K,t*=K);
		if(op == 1){
			scanf("%d",&v);
			for(;x*t<=n && (x&lB);){
				t1[x*t] ^= v,x+=x%K;
				for(;x%K==0;x/=K,t*=K);
			}
			if(x*t <= n) Add(rt[t*Find(x)],1,n,x*t,v);
		}
		else{
			int ans = 0;
			for(;x;){
				if(x&lB) ans ^= t1[x*t];
				else ans ^= Query(rt[t*Find(x)],1,n,x*t);
				x-=x%K;
				for(;x&&x%K==0;x/=K,t*=K);
			}
			printf("%d\n",ans);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章