【学习笔记】模拟赛题解

混乱邪恶

构造题的第一步总是最难想的。

考虑 n n n是偶数的情况,否则添加一个 0 0 0

首先把数从大到小排序,然后相邻的两个数配对,记其差为 s i s_i si

注意到 n ∈ [ 2 3 m , m ] n\in [\frac{2}{3}m,m] n[32m,m],因此 ∑ s i ≤ m − n 2 < n \sum s_i\le m-\frac{n}{2}<n sim2n<n

这就很有意思了。也就是说至少存在 n 2 \frac{n}{2} 2n 1 1 1,同时注意到 s i s_i si最大值不超过 m − n m-n mn

显然 n 2 ≥ m − n \frac{n}{2}\ge m-n 2nmn。那么可以设计如下算法:

s i s_i si从大到小排序,如果当前 s u m < 0 sum<0 sum<0,那么加上 s i s_i si,如果 s u m ≥ 0 sum\ge 0 sum0那么减去 s i s_i si

当然本题还有另一种构造方案。具体是让最大值减最小值,这样每次迭代完 ∑ s i \sum s_i si不超过数的个数的两倍。最后规约到 2 2 2个数的情况即可。

代码:

我信仰什么,我便实现哪种方法。

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
using namespace std;
int n,m,a[1000005],id[1000005],res[1000005];
ll sum;
vector<int>v2;
struct node{
	int x,y,d;
	bool operator <(const node &a)const {
		return d>a.d;
	}
};
vector<node> v3;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	memset(res,-1,sizeof res);
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		int x;cin>>x,id[x]=i,a[x]=1;
	}
	for(int i=m;i>=1;i--) {
		if(a[i]) {
			v2.pb(i);
		}
	}
	for(int i=0;i+1<v2.size();i+=2) {
		v3.pb({v2[i],v2[i+1],v2[i]-v2[i+1]});
	}
	if(v2.size()&1) {
		v3.pb({v2.back(),0,v2.back()});
	}sort(v3.begin(),v3.end());
	for(auto &x:v3) {
		if(sum<0) sum+=x.d,res[id[x.x]]=1;
		else sum-=x.d,res[id[x.y]]=1;
	}
	if(sum==0) {
		cout<<"NP-Hard solved"<<endl;
		for(int i=1;i<=n;i++) cout<<res[i]<<' ';
	}
	else {
		cout<<"Chaotic evil";
	}
}

鸽子

sb数据结构题

类比 z k w zkw zkw线段树,可以把 l → r l\to r lr的路径提出来。

然后大力重链剖分。具体是每条重链维护两棵线段树,分别维护与这条链相邻的左子树和右子树。(若一个点的左子树不在链上则这个点维护左子树,否则这个点维护右子树)

跳轻链的过程是单点修改+单点查询,直接用数组维护即可。

注意到我维护的是两个不同的方向,所以把两个部分的答案加起来即可。

复杂度 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2n)

代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
using namespace std;
int n,m,rt,num,rk[400005];
int ls[400005],rs[400005];
int dfn[400005],siz[400005],son[400005],num2;
int vs[400005],tp[400005],dep[400005],fa[400005];
ll s[1600020];
struct sgt{
	ll t[1600020],tag[1600020],siz[1600020];
	void add(int p,ll x) {
		t[p]+=siz[p]*x,tag[p]+=x;
	}
	void pushdown(int p) {
		if(tag[p]) add(p<<1,tag[p]),add(p<<1|1,tag[p]),tag[p]=0;
	}
	void ins(int p,int l,int r,int x,int y) {
		siz[p]+=y;if(l==r) return;
		int mid=l+r>>1;x<=mid?ins(p<<1,l,mid,x,y):ins(p<<1|1,mid+1,r,x,y); 
	}
	void upd(int p,int l,int r,int ql,int qr,ll x) {
		if(ql>qr) return;
		if(ql<=l&&r<=qr) {
			add(p,x);
			return;
		}int mid=l+r>>1;pushdown(p);
		if(ql<=mid) upd(p<<1,l,mid,ql,qr,x);
		if(mid<qr) upd(p<<1|1,mid+1,r,ql,qr,x);
		t[p]=t[p<<1]+t[p<<1|1];
	}
	ll qry(int p,int l,int r,int ql,int qr) {
		if(ql>qr) return 0;
		if(ql<=l&&r<=qr) return t[p];
		int mid=l+r>>1;pushdown(p);
		if(qr<=mid) return qry(p<<1,l,mid,ql,qr);
		if(mid<ql) return qry(p<<1|1,mid+1,r,ql,qr);
		return qry(p<<1,l,mid,ql,qr)+qry(p<<1|1,mid+1,r,ql,qr); 
	}
}T[2];
void upd(int x,ll d) {
    s[x]+=d*siz[son[x]];
}
void dfs(int u,int topf) {
	fa[u]=topf,dep[u]=dep[topf]+1;
	if(!ls[u]) {
		siz[u]=1,rk[++num]=u;
		return;
	}dfs(ls[u],u),dfs(rs[u],u);siz[u]+=siz[ls[u]]+siz[rs[u]];
	son[u]=(siz[ls[u]]>siz[rs[u]])?ls[u]:rs[u];
}
void dfs2(int u,int topf) {
	dfn[u]=++num2,tp[u]=topf;
	if(!ls[u]) return;
	if(ls[u]==son[u]) dfs2(ls[u],topf),dfs2(rs[u],rs[u]),T[1].ins(1,1,n,dfn[u],siz[rs[u]]);
	else dfs2(rs[u],topf),dfs2(ls[u],ls[u]),T[0].ins(1,1,n,dfn[u],siz[ls[u]]);
}
void modify(int x,int y,ll d) {
	int fx=tp[x],fy=tp[y];
	while(fx!=fy) {
		if(dep[fx]>dep[fy]) {
			T[1].upd(1,1,n,dfn[fx],dfn[x]-1,d),x=fa[fx];
			if(tp[x]!=tp[y]&&rs[x]==son[x]) {
				upd(x,d);
			}
		}
		else {
			T[0].upd(1,1,n,dfn[fy],dfn[y]-1,d),y=fa[fy];
			if(tp[x]!=tp[y]&&ls[y]==son[y]) {
				upd(y,d);
			}
		}fx=tp[x],fy=tp[y];
	}
	if(dep[x]>dep[y]) {
		T[1].upd(1,1,n,dfn[y]+1,dfn[x]-1,d);
	}
	else {
		T[0].upd(1,1,n,dfn[x]+1,dfn[y]-1,d);
	}
}
ll qry(int x,int y) {
	int fx=tp[x],fy=tp[y];ll res=0;
	while(fx!=fy) {
		if(dep[fx]>dep[fy]) {
			res+=T[1].qry(1,1,n,dfn[fx],dfn[x]-1),x=fa[fx];
			if(tp[x]!=tp[y]&&rs[x]==son[x]) {
				res+=s[x];
			}
		}
		else {
			res+=T[0].qry(1,1,n,dfn[fy],dfn[y]-1),y=fa[fy];
			if(tp[x]!=tp[y]&&ls[y]==son[y]) {
				res+=s[y];
			}
		}fx=tp[x],fy=tp[y];
	}
	if(dep[x]>dep[y]) {
		res+=T[1].qry(1,1,n,dfn[y]+ 1,dfn[x]-1);
	}
	else {
		res+=T[0].qry(1,1,n,dfn[x]+1,dfn[y]-1);
	}
	return res;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;memset(vs,-1,sizeof vs);
	for(int i=1;i<n;i++) {
		cin>>ls[n+i]>>rs[n+i];
		vs[ls[n+i]]=0,vs[rs[n+i]]=1;
	}for(int i=n+1;i<2*n;i++) {
		if(vs[i]==-1) rt=i;
	}n=2*n-1;int x=++n,y=++n,z=++n,w=++n;ls[x]=rt,rs[x]=y,ls[z]=w,rs[z]=x;dfs(z,0),dfs2(z,z);
	for(int i=1;i<=m;i++) {
		int op,l,r,d;
		cin>>op>>l>>r;
		if(op==1) {
			cin>>d;
			modify(rk[l],rk[r+2],d);
		}
		else {
			cout<<qry(rk[l],rk[r+2])<<endl;
	    }
	}
}
posted @ 2022-09-24 17:20  仰望星空的蚂蚁  阅读(15)  评论(0)    收藏  举报  来源