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;
}
posted @ 2022-10-06 13:15  FxorG  阅读(133)  评论(0编辑  收藏  举报