• 2022牛客OI赛前集训营提高组(第一场)


    教练给我们打的离线(

    数据分治忘删,多 solve 一次,明明复杂度 O(n^3) 偏偏不想压空间 敬重桥廊

    不挂的话,70+100+50+50,挂了是 70+100+0+0/cy

    推销一下 https://www.cnblogs.com/RuntimeErr/p/16757799.html

    A

    神笔题,不说了,没意义。

    B

    你会想要树形 dp,但是你发现其实儿子的子树(除去儿子)对当前答案没有任何影响,于是你会想到我们可以钦定点,然后仅保留这个点和这个点的儿子,钦定这些点是否跳,来得到答案。不重不漏考虑其他点乱跳,即我们只是选取了其一部分来观察这一部分对答案的贡献而已。

    然后你会发现你要枚举子集,然后你发现是异或,然后典中典,枚举位,组合数一下就可以了。

    #include <bits/stdc++.h>
    #define int long long
    #define pb push_back
    using namespace std;
    const int N=(int)(1e5+5),mod=(int)(1e9+7);
    vector<int>g[N];
    int n,a[N],v[N],sz[N],ans;
    
    int fpow(int x,int y) {
    	if(y<=0) return 1;
    	int res=1; x%=mod;
    	while(y) {
    		if(y&1) res=res*x%mod;
    		y>>=1; x=x*x%mod;
    	} return res;
    }
    
    void dfs(int x,int ff) {
    	int tot=0; sz[x]=1; 
    	for(int y:g[x]) {
    		if(y==ff) continue ;
    		dfs(y,x); sz[x]+=sz[y];
    	}
    	for(int y:g[x]) {
    		if(y==ff) continue ;
    		v[++tot]=a[y];
    	}
    	int qwq;
    	if(x==1) qwq=fpow(2,n-1-tot);
    	else qwq=fpow(2,n-2-tot);
    	int res=0;
    	if(x!=1) {
    		for(int i=0;i<=30;i++) {
    			int cnt1=0,cnt0=0;
    			for(int j=1;j<=tot;j++) {
    				if((v[j]>>i)&1) ++cnt1;
    				else ++cnt0;
    			}
    			if(cnt1>=1) {
    				res=(res+(1ll<<i)*cnt1%mod*(fpow(2,cnt0)-1)%mod)%mod;
    				res=(res+(1ll<<i)*(fpow(2,cnt1-1)-cnt1)%mod*fpow(2,cnt0)%mod)%mod;
    			}
    		}
    	}
    	for(int i=0;i<=30;i++) {
    		int cnt1=0,cnt0=0;
    		for(int j=1;j<=tot;j++) {
    			if((v[j]>>i)&1) ++cnt1;
    			else ++cnt0;
    		}
    		if((a[x]>>i)&1) {
    			res=(res+(1ll<<i)*(fpow(2,cnt0)-1)%mod)%mod;
    			if(cnt1>=2) {
    				res=(res+(1ll<<i)*(fpow(2,cnt1-1)-1)%mod*fpow(2,cnt0)%mod)%mod;
    			}
    		} else {
    			if(cnt1) {
    				res=(res+(1ll<<i)*fpow(2,cnt1-1)%mod*fpow(2,cnt0)%mod)%mod;
    			}
    		}
    	}
    //	cout<<x<<" "<<res*qwq<<'\n';
    	ans=(ans+res*qwq%mod)%mod;
    }
    
    signed main() {
    	
    	cin.tie(0); ios::sync_with_stdio(false);
    	cin>>n;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	for(int i=2;i<=n;i++) {
    		int x; cin>>x;
    		g[x].pb(i); g[i].pb(x);
    	}
    	dfs(1,0);
    	ans=(ans%mod+mod)%mod;
    	cout<<ans;
    	return 0;
    } 
    

    D

    image

    假如你不会线段树维护分段函数,假如你不会不带 \(\log\) 的合并,建议跟我一样分块,但是块长和询问次数你要卡好。

    显然我们有 \(B\log n=\dfrac{n}{B}+B\),解得 \(B=\sqrt{\dfrac{n}{\log n-1}}\),很厉害啊。

    然后我试了一下 \(B=\sqrt{n}\),发现只能 55。充分说明了平衡的重要性(

    #include <bits/stdc++.h>
    //#define int long long 
    #define pb push_back
    using namespace std;
    const int N=(int)(3e5+5),M=5002;
    struct node {
    	int op,x;
    }a[N];
    struct nd {
    	int L,R,b,lv,rv;
    	nd() {
    		
    	}
    	nd(int xL,int xR,int xb,int xlv,int xrv) {
    		L=xL; R=xR; b=xb; lv=xlv; rv=xrv;
    	}
    }val[M];
    int n,q,bl,id[N],L[M],R[M];
    
    int qry(int idx,int x) {
    	for(int i=L[idx];i<=R[idx];i++) {
    		if(a[i].op==1) x+=a[i].x;
    		else if(a[i].op==2) x=min(x,a[i].x);
    		else x=max(x,a[i].x); 
    	} return x;
    }
    
    nd query(int idx) { // [L,R]N :y=x+b
    	int L=1,R=(int)(1e8),q1=qry(idx,1),q2=qry(idx,2),qR=qry(idx,R),qR1=qry(idx,R-1);
    	if(q1!=q2) { //3/1
    		if(qR!=qR1) {
    			int qwq=q1-1;
    			return nd(1,(int)(1e8),qwq,0,0);
    		} else {
    			int l=1,r=(int)(1e8),res=0,qwq=qR;
    			while(l<=r) {
    				int mid=(l+r)>>1;
    				if(qry(idx,mid)==qwq) res=mid,r=mid-1;
    				else l=mid+1;
    			}
    //			if(x>=res) return qwq;
    			int b=qry(idx,res-1)-(res-1);
    			return nd(1,res-1,b,0,qR); 
    		}
    	} else {
    		if(qR!=qR1) {
    			int l=1,r=(int)(1e8),res=0,qwq=q1;
    			while(l<=r) {
    				int mid=(l+r)>>1;
    				if(qry(idx,mid)==qwq) res=mid,l=mid+1;
    				else r=mid-1; 
    			}
    //			if(x<=res) return qwq;
    			int b=qry(idx,res+1)-(res+1);
    			return nd(res+1,(int)(1e8),b,q1,0);
    		} else {
    			int l=1,r=(int)(1e8),qwq=q1,res=0;
    			while(l<=r) {
    				int mid=(l+r)>>1;
    				if(qry(idx,mid)==qwq) res=mid,l=mid+1;
    				else r=mid-1; 
    			}
    			L=res+1;
    			l=1; r=(int)(1e8); qwq=qR; res=0;
    			while(l<=r) {
    				int mid=(l+r)>>1;
    				if(qry(idx,mid)==qwq) res=mid,r=mid-1;
    				else l=mid+1;
    			}
    			R=res-1;
    //			if(L<=x&&x<=R) {
    //				qwq=qry(L)-L;
    //				return x+qwq;
    //			}
    //			if(x<L) return qry(1);
    //			if(x>R) return qry((int)(1e8));
    			qwq=qry(idx,L)-L;
    			return nd(L,R,qwq,q1,qR);
    		}
    	}
    }
    
    int queryx(int idx,int x) {
    	if(val[idx].L<=x&&x<=val[idx].R) return x+val[idx].b;
    	if(x<val[idx].L) return val[idx].lv;
    	return val[idx].rv;
    }
    
    int qryx(int x) {
    	for(int i=1;i<=id[n];i++) {
    		x=queryx(i,x);
    	}
    	return x;
    }
    
    signed main() {
    //	freopen("1.in","r",stdin);
    //	freopen("xgf.out","w",stdout); 
    	cin.tie(0); ios::sync_with_stdio(false);
    	cin>>n; bl=sqrt(n/max(1,(int)log2(n)-1));
    	for(int i=1;i<=n;i++) {
    		cin>>a[i].op>>a[i].x; id[i]=(i-1)/bl+1;
    	}
    	for(int i=1;i<=id[n];i++) L[i]=(i-1)*bl+1,R[i]=i*bl;
    	for(int i=1;i<=id[n];i++) val[i]=query(i);
    	cin>>q;
    	while(q--) {
    		int op; cin>>op;
    		if(op!=4) {
    			int x,y; cin>>x>>y;
    			a[x].op=op; a[x].x=y;
    			val[id[x]]=query(id[x]);
    		} else {
    			int x; cin>>x;
    			cout<<qryx(x)<<'\n';
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    设计模式--单例模式Singleton
    CSS选择器
    操作数据表
    HTML
    Shell学习
    LINUX常用命令
    多线程-互斥变量
    多线程-临界区
    每天一个linux命令:file(11)
    JavaScript设计模式小抄集(持续更新)
  • 原文地址:https://www.cnblogs.com/xugangfan/p/16757448.html
Copyright © 2020-2023  润新知