11.22模拟赛

T1

给定一棵 \(n\) 个点的树,点有颜色,问有哪些 \(u\) 满足,对于任意的 \(v\),路径 \((u,v)\) 上不出现重复颜色。

对于所有数据,满足 \(1 \leq n \leq 2 \times 10^5, 1 \leq c_i \leq n\)

题解

考虑用样的颜色会使得那些点不能成为答案,思考之后我们可以得到这个性质,现在我们以 \(1\) 为根:

  • 对于相同颜色的点考虑,如果这个点的子树有相同颜色点,那么这个点的非子树节点无解。
  • 如果这个点的非子树节点有相同颜色点,那么这个点的子树节点无解。

但是会有一个 corner case,就是根节点的判断没有非子树的部分,所以会错。考虑再用 \(2\) 为根跑一次就行了。

为了处理上面的判断,我们可以用两个树状数组维护。

code:

#include<bits/stdc++.h>
#define pb push_back
#define int long long
#define lbt(x) (x&(-x))
#define m(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int N=5e5+10;
int n,m,k,T,a[N],t[N],t1[N],sum,dfn[N],tot,out[N],res[N];
vector<int> g[N],col[N],ans;
void upd(int i,int x){while(i<N){t[i]+=x;i+=lbt(i);}}
int sc(int i){int ans=0;while(i>0){ans+=t[i];i-=lbt(i);}return ans;}
int query(int l,int r){return sc(r)-sc(l-1);}
void upd1(int i,int x){while(i<N){t1[i]+=x;i+=lbt(i);}}
int sc1(int i){int ans=0;while(i>0){ans+=t1[i];i-=lbt(i);}return ans;}
void add1(int l,int r,int x){upd1(l,x);upd1(r+1,-x);}
void dfs(int u,int fa){
	dfn[u]=++tot;
	for(int v:g[u]){
		if(v==fa) continue;
		dfs(v,u);
	}out[u]=tot;
}
void solve(int x){
	tot=0;dfs(x,0);m(t1);m(t);
	rep(i,1,n){
		for(int u:col[i]) upd(dfn[u],1);
	    for(int u:col[i]){
	    	int x=query(dfn[u]+1,out[u]);
			if(x>=1){
				add1(1,dfn[u],1);add1(out[u]+1,n,1);
			}if(col[i].size()-x>1){
				add1(dfn[u],out[u],1);
			}
		}for(int u:col[i]) upd(dfn[u],-1);
	}rep(i,1,n){
		if(sc1(dfn[i])>0){
			res[i]=1;
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	freopen("problem.in","r",stdin);
	freopen("problem.out","w",stdout);
    cin>>n;
	rep(i,1,n){
		int x;cin>>x;
		col[x].pb(i);
	}rep(i,1,n-1){
		int u,v;cin>>u>>v;
		g[u].pb(v);g[v].pb(u);
	}solve(1);solve(2);
	rep(i,1,n){
		if(res[i]==0){
			ans.pb(i);sum++;
		}
	}cout<<sum<<'\n';
	for(int u:ans){
		cout<<u<<" ";
	}
	return 0;
}

T2

荷塘是一个平面直角坐标系,其中有 \(n\) 条鱼,编号为 \(1, 2, \ldots, n\),位置用一个点 \((x_i, y_i)\) 表示(可以重复)。它们听路过的米奇提到 \(\text{“}\) 平面最远点对 \(\text{”}\),于是想亲身实践一下——进行 \(m\) 次操作,每次为以下两种之一:

  • 充分发扬鱼类智慧,将编号在 \([l, r]\) 中的鱼的位置绕原点逆时针旋转 \(90^\circ\)
  • 询问编号在 \([l, r]\) 中的鱼两两之间(包括自己和自己)的最大曼哈顿距离,即:

\[\max_{l \leq i \leq j \leq r} \{ |x_i - x_j| + |y_i - y_j| \} \]

由于鱼的记忆只有七秒,难以进行大量的运算,所以它们想请你帮忙给出答案。

对于 \(100\%\) 的数据,满足 \(1 \leq n, m \leq 2 \times 10^5, 1 \leq x_i, y_i \leq 10^8, 1 \leq l \leq r \leq n\)

题解

先套路的转化为切比雪夫距离,那么我们的式子就变成了:

\[\max_{l \leq i \leq j \leq r} \{ \max(|x_i - x_j| , |y_i - y_j|) \} \]

发现只和一个值有关,所以只需要维护区间新的 \(x,y\) 的最大最小值就行了。现在考虑怎么做翻转操作。我们同时维护这些区间翻转 \(0\degree,90\degree,180\degree,270\degree\) 的值,翻转之后值轮换一下就好了,直接用线段树维护即可。

code:

#include<bits/stdc++.h>
#define fi first
#define se second
#define ls (p<<1)
#define rs (p<<1|1)
#define int long long
#define pii pair<int,int>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int N=5e5+10;
int n,m,q,T;pii a[N];
vector<int> g[N];
struct tree{
	int u,l,d,r,laz;
	friend tree operator+(tree a,tree b){
		tree tmp;
		tmp.u=max(a.u,b.u),tmp.l=min(a.l,b.l);
		tmp.d=min(a.d,b.d),tmp.r=max(a.r,b.r);
        return tmp;
	}
}t[N<<2];
void build(int p,int l,int r){
	if(l==r){
		int x=a[l].fi,y=a[l].se;
		t[p]={x+y,x-y,x+y,x-y,0};return;
	}int mid=l+r>>1;
	build(ls,l,mid);build(rs,mid+1,r);
	t[p]=t[ls]+t[rs];
}
void solve(int p,int x){
	tree tmp=t[p];
	t[p].laz=(t[p].laz+x)%4;
	while(x--){
		t[p].u=tmp.r;t[p].l=-tmp.u;
        t[p].d=tmp.l;t[p].r=-tmp.d;
        tmp=t[p];
	}
}
void pushdown(int p){
	if(t[p].laz==0) return;
	solve(ls,t[p].laz);solve(rs,t[p].laz);
	t[p].laz=0;
}
void upd(int p,int l,int r,int x,int y){
	if(x<=l&&r<=y){
		solve(p,1);return;
	}int mid=l+r>>1;pushdown(p);
	if(x<=mid) upd(ls,l,mid,x,y);
	if(y>mid) upd(rs,mid+1,r,x,y);
	t[p]=t[ls]+t[rs]; 
}
tree query(int p,int l,int r,int x,int y){
	if(x<=l&&r<=y) return t[p];
	int mid=l+r>>1;pushdown(p);
	if(y<=mid) return query(ls,l,mid,x,y);
	else if(x>mid) return query(rs,mid+1,r,x,y);
	else return query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	freopen("fish.in","r",stdin);
    freopen("fish.out","w",stdout);
    cin>>n>>q;
    rep(i,1,n){
    	int x,y;cin>>x>>y;
    	a[i]={x,y};
	}build(1,1,n);
	while(q--){
		int op,l,r;cin>>op>>l>>r;
		if(op==1) upd(1,1,n,l,r);
		else{
			tree res=query(1,1,n,l,r);
			cout<<max(res.u-res.d,res.r-res.l)<<'\n';
		} 
	}
	return 0;
}

T3

T4

posted @ 2025-11-22 16:07  NeeDna  阅读(18)  评论(0)    收藏  举报