zoukankan      html  css  js  c++  java
  • 北校门外的回忆

    这篇题解我真的是写了好多遍,每次快写好的时候就各种情况然后写的消失了

    题目链接

    这题要你求错误代码的结果,所以不是维护前缀异或和

    这题暴力时间上是可以过的,但是空间不行

    想到用动态开点线段树维护树状数组

    这下时间过不去了

    x+lowbit(x)相当于x的最低位*2,x向x+lowbit(x)连边

    在x不断向x+lowbit(x)跳的时候,lowbit(x)的非零位数字不断*2 mod k

    当k是奇数时,2与k互质,所以如果2a=2b(mod k),a=b(mod k)

    所以x -> x+lowbit(x)会形成若干不相交的链

    当k是偶数时,链会相交,就处理出不相交的链,用动态开点线段树维护

    对于不在链上的点就暴力跳到链上然后区间更新,在跳不超过log_2(k)∗log_k(n)=log_2(n)次后一定会跳到一条链上或跳出去。

    在链上的点就求出其所在的链和它在链中的位置,然后区间更新、

    lowbit(x)如果末尾有零,那x所在的链一定与模掉0之后的链是相似的,只要处理完后再把0乘回来即可

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,j,k) for(int i=j;i<=k;++i)
    typedef long long ll;
    typedef double db;
    char cch;
    inline int rd(){
    	int x=0,fl=1;
    	cch=getchar();
    	while(cch>'9'||cch<'0'){
    		if(cch=='-') fl=-1;
    		cch=getchar();
    	}
    	while(cch>='0'&&cch<='9') x=(x<<3)+(x<<1)+cch-'0',cch=getchar();
    	return x*fl;
    }
    const int N=2e5+5;
    int st,dis,n,k,sz,pw[N],bz1[N][20],bz2[N][20],cnt[N],len[N],a[N];
    bool vis[N];
    struct tree{
    	int s,l,r;
    }tr[N*80];
    inline int lowbit(int x){//最低非零位上的数字 
    	while(x%k==0) x/=k;
    	return x%k; 
    }  
    inline int lowbitv(int x){//最低非零位的值 
    	int lg=1;
    	while(x%k==0) x/=k,lg*=k;
    	return x%k*lg;
    }
    inline void getst(int x){
    	int lg=1;
    	while(x%k==0) x/=k,lg*=k;//零是不影响的 
    	st=lowbit(x);//在哪条链 
    	int u=(x-st)/k;//要进几次位
        dis=u/cnt[st]*len[st]+1;//往回跳了多少个点
        u%=cnt[st];//剩下的不足一个环的 就倍增往回跳 
        for(int i=18;i>=0;i--) if(bz2[st][i]<=u) u-=bz2[st][i],dis+=(1<<i),st=bz1[st][i];
        st*=lg;
    }
    void init(){
    	int x,tot,w,to;
    	rep(i,1,k){
    		x=i;
    		while(x%2==0) ++pw[i],x/=2;
    	}
    	for(int i=1;i<k;++i) if(!vis[i]&&pw[i]>=pw[k]){
    		tot=0,w=0,a[++tot]=i,x=(i<<1)%k;
    		while(!vis[x]) 
    		vis[x]=1,a[++tot]=x,x=(x<<1)%k;//a存的是lowbit值形成的一个环
    		rep(j,1,tot) w+=(a[j]<<1)>=k;//注意是往回跳,所以 to存的是 a[(j-1+tot)%tot]
    		rep(j,1,tot) cnt[a[j]]=w,len[a[j]]=tot,to=a[(j-1+tot)%tot],bz1[a[j]][0]=to,bz2[a[j]][0]=(to<<1)/k;//len是这个环点长度,cnt是完整跳一个环会进多少位 
    		rep(h,1,18) rep(j,1,tot) bz1[a[j]][h]=bz1[bz1[a[j]][h-1]][h-1],bz2[a[j]][h]=bz2[bz1[a[j]][h-1]][h-1]+bz2[a[j]][h-1];//每个a[i]都更新,都作为链首
    	}//bz是往回跳会跳到哪个值的倍增数组,bz2是往回跳多少步会有多少进位的倍增数组 
    	 
    }
    void ins(int &d,int l,int r,int ql,int qr,int z){
        if (!d) d=++sz;
        if (ql<=l&&r<=qr){tr[d].s^=z;return;}
        int mid=(l+r)/2;
        if (ql<=mid) ins(tr[d].l,l,mid,ql,qr,z);
        if (qr>mid) ins(tr[d].r,mid+1,r,ql,qr,z);
    }
    int qry(int d,int l,int r,int x){ 
        if(l==r||!d) return tr[d].s;
        int mid=(l+r)/2;
        if(x<=mid) return qry(tr[d].l,l,mid,x)^tr[d].s;
        else return qry(tr[d].r,mid+1,r,x)^tr[d].s;
    }
    int main(){
    	n=rd();int ans,q=rd(),x,tmp,val,op,rt,root=0;k=rd();
    	init();
    	while(q--){
    		op=rd();
    		if(op==1){
    			x=rd(),val=rd();
    			while (x<=n&&pw[lowbit(x)]<pw[k]){//不在链上的点 
                    ins(root,1,n,x,x,val);//单点修改 
                    x+=lowbitv(x);
                }
                if(x>n) continue;//跳出n了
    			getst(x);//st是链首,dis是x在链中的位置 
    			rt=qry(root,1,n,st),/*查找st所在链对应的线段树的根*/tmp=rt,ins(rt,1,n,dis,n,val);
    			if(!tmp)ins(root,1,n,st,st,rt);//root是维护rt的,单点查询,这样写可以省一些代码 
    		}
    		else{
    			x=rd(),ans=0; 
    			while(x){
                    if (pw[lowbit(x)]<pw[k]) ans^=qry(root,1,n,x);//对于那些不在链上的点,root维护的就是点的值 
                    else{
                        getst(x);
                        int rt=qry(root,1,n,st);//因为x与x+lowbit(x)在同一条链,但是x与x+lowbit(x)-lowbit(x+lowbit(x))不一定在同一条链 
                        if(rt) ans^=qry(rt,1,n,dis);//所以单点查询 
                    }
                    x-=lowbitv(x);
                }
                printf("%d
    ",ans);
    		}
    	}
    } 
    
  • 相关阅读:
    现代软件工程 第一章 概论 第4题——邓琨
    现代软件工程 第一章 概论 第9题——邓琨
    现代软件工程 第一章 概论 第7题——张星星
    现代软件工程 第一章 概论 第5题——韩婧
    hdu 5821 Ball 贪心(多校)
    hdu 1074 Doing Homework 状压dp
    hdu 1074 Doing Homework 状压dp
    hdu 1069 Monkey and Banana LIS变形
    最长上升子序列的初步学习
    hdu 1024 Max Sum Plus Plus(m段最大子列和)
  • 原文地址:https://www.cnblogs.com/Doingdong/p/10710203.html
Copyright © 2011-2022 走看看