首页 > 其他分享 >Codeforces 1439E - Cheat and Win

Codeforces 1439E - Cheat and Win

时间:2023-05-25 22:57:29浏览次数:45  
标签:1439E return get Cheat lim Codeforces xb int ya

模拟赛放了道 *3500,结果全场都切了,非常恐怖。

首先考虑怎么样的树是合法的,打个表发现 SG 函数值为 \(\sum_{d}2^d·(\text{深度为 d 的点个数}\bmod 2)\),换句话说后手必胜当且仅当每种深度的点数都是偶数。

于是实际上我们只用建出虚树之后树上差分一下求出每个点被覆盖的情况,进而能够求出答案。

考虑如果我们要建出虚树需要实现哪些功能:

  • 快速求一个点的深度,发现很傻,\((x,y)\) 的深度实际上就是 \(x+y\)。

  • 快速求两个点的 LCA。由于给定的树是一个分形,所以考虑查询的两个点在当前分形(假设大小为 \(2^k\))三个部分中的哪一个,如果在同一个部分则进入那一个部分继续递归,否则 LCA 显然在左上角那个部分中,把右上角的点提到 \((0,2^{k-1}-1)\),把左下角的点提到 \((2^{k-1}-1,0)\),然后继续递归即可。

  • 比较两个点的 DFS 序,如果两者存在祖先后代关系那么深度较小的那个靠前,否则同理在分形上跑一下。

由于比较 DFS 序需要一个 \(\log\),再加上排序一个 \(\log\),总共是 2log,可以通过。

所以这题实际上是一个巨大缝合怪,配不上其 *3500 的难度(

具体实现的时候写得比较累赘,可能和上面说得不太一样,看看就好。

const int MAXN=4e5;
int n,lc[MAXN+5];pii p[MAXN+5],pt[MAXN+5];
map<pii,int>id;int idcnt=0;
int getid(int x,int y){
	if(id[mp(x,y)])return id[mp(x,y)];
	else return id[mp(x,y)]=++idcnt,pt[idcnt]=mp(x,y),idcnt;
}
pii getlca(int xa,int ya,int xb,int yb,int d){
	if(!d)return mp(0,0);
	int lim=(1<<d-1);
	if(xa<lim&&ya<lim&&xb<lim&&yb<lim)return getlca(xa,ya,xb,yb,d-1);
	else if(xa>=lim&&xb>=lim){
		pii p=getlca(xa-lim,ya,xb-lim,yb,d-1);
		return mp(p.fi+lim,p.se);
	}else if(ya>=lim&&yb>=lim){
		pii p=getlca(xa,ya-lim,xb,yb-lim,d-1);
		return mp(p.fi,p.se+lim);
	}else if((xa>=lim||ya>=lim)&&(xb>=lim||yb>=lim))return mp(0,0);
	else{
		if(xb<lim&&yb<lim)swap(xa,xb),swap(ya,yb);
		if(xb>=lim)return getlca(xa,ya,lim-1,0,d-1);
		else return getlca(xa,ya,0,lim-1,d-1);
	}
}
bool getcmp(int xa,int ya,int xb,int yb,int d){
	if(!d)return 0;
	int lim=(1<<d-1);
	if(xa<lim&&ya<lim&&xb<lim&&yb<lim)return getcmp(xa,ya,xb,yb,d-1);
	else if(xa>=lim&&xb>=lim)return getcmp(xa-lim,ya,xb-lim,yb,d-1);
	else if(ya>=lim&&yb>=lim)return getcmp(xa,ya-lim,xb,yb-lim,d-1);
	else{
		int ida=((xa>=lim)?0:((ya>=lim)?2:1));
		int idb=((xb>=lim)?0:((yb>=lim)?2:1));
		return ida<idb;
	}
}
vector<int>g[MAXN+5];int rt;
int build(vector<tuple<int,int,int> >v,int cx,int cy,int d){
	if(v.empty())return 0;
	if(v.size()==1)return get<2>(v[0]);int lim=1<<d-1;
	vector<tuple<int,int,int> >A,L,R;
	for(tuple<int,int,int>t:v){
		if(get<0>(t)>=lim)L.pb(mt(get<0>(t)-lim,get<1>(t),get<2>(t)));
		else if(get<1>(t)>=lim)R.pb(mt(get<0>(t),get<1>(t)-lim,get<2>(t)));
		else A.pb(t);
	}
	if(L.empty()&&R.empty())return build(A,cx,cy,d-1);
	else if(A.empty()&&R.empty())return build(L,cx+lim,cy,d-1);
	else if(A.empty()&&L.empty())return build(R,cx,cy+lim,d-1);
	else{
		int a=build(A,cx,cy,d-1),l=build(L,cx+lim,cy,d-1),r=build(R,cx,cy+lim,d-1);
		if(l){pii mx=mp(-1,0);for(auto t:A)if(get<1>(t)==0)chkmax(mx,mp(get<0>(t),get<2>(t)));g[mx.se].pb(l);}
		if(r){pii mx=mp(-1,0);for(auto t:A)if(get<0>(t)==0)chkmax(mx,mp(get<1>(t),get<2>(t)));g[mx.se].pb(r);}
		return a;
	}
}
int mark[MAXN+5],vis[MAXN+5],fa[MAXN+5];
void dfs(int x,int f){fa[x]=f;for(int y:g[x])dfs(y,x),mark[x]+=mark[y];}
map<int,int>dif;
void add(int l,int r){dif[l]^=1;dif[r+1]^=1;}
bool cmp(int x,int y){
	if(x==0)return 0;
	pii lca=getlca(pt[x].fi,pt[x].se,pt[y].fi,pt[y].se,30);
	if(lca==pt[x])return 1;if(lca==pt[y])return 0;
	return getcmp(pt[x].fi,pt[x].se,pt[y].fi,pt[y].se,30);
}
int main(){
	scanf("%d",&n);vector<int>v;map<int,int>in;
	for(int i=1,xa,ya,xb,yb;i<=n;i++){
		scanf("%d%d%d%d",&xa,&ya,&xb,&yb);
		p[i].fi=getid(xa,ya);p[i].se=getid(xb,yb);
		pii pp=getlca(xa,ya,xb,yb,30);lc[i]=getid(pp.fi,pp.se);
		if(!in[p[i].fi])v.pb(p[i].fi),in[p[i].fi]=1;
		if(!in[p[i].se])v.pb(p[i].se),in[p[i].se]=1;
	}
	sort(v.begin(),v.end(),cmp);
	for(int i=1;i<v.size();i++){
		pii pp=getlca(pt[v[i-1]].fi,pt[v[i-1]].se,pt[v[i]].fi,pt[v[i]].se,30);
		getid(pp.fi,pp.se);
	}
	vector<tuple<int,int,int> >vec;
	for(int i=1;i<=idcnt;i++)vec.pb(mt(pt[i].fi,pt[i].se,i));
	rt=build(vec,0,0,30);
	for(int i=1;i<=n;i++)vis[lc[i]]=1,mark[p[i].fi]++,mark[p[i].se]++,mark[lc[i]]-=2;
	dfs(rt,0);
	for(int i=1;i<=idcnt;i++){
		if(vis[i]||mark[i])add(pt[i].fi+pt[i].se,pt[i].fi+pt[i].se);
		if(mark[i])add(pt[fa[i]].fi+pt[fa[i]].se+1,pt[i].fi+pt[i].se-1);
	}
	int sum=0;
	for(pii pp:dif)if(pp.se)sum++;
	if(!sum)puts("0");
	else{
		sum--;
		if(!dif[0])++sum;
		printf("%d\n",sum);
	}
	return 0;
}
/*
*#*#############
#.*.#.#.#.#.#.#.
#*..##..##..##..
#...*...#...#...
####....####....
#.#.....#.#.....
##......##......
#.......#.......
########........
#.#.#.#.........
##..##..........
#...#...........
####............
#.#.............
##..............
#...............
*/

标签:1439E,return,get,Cheat,lim,Codeforces,xb,int,ya
From: https://www.cnblogs.com/tzcwk/p/Codeforces-1439E.html

相关文章

  • 【题解】Codeforces Round 737 (CF1557)
    VP情况:solve:4/5rank:431st评价:VP了一下,我这个shaberB直接5发罚时,耽误了二十多分钟,以及被D各种细节差点搞死。A.EzzatandTwoSubsequences(*800)题目描述:给定一个序列,将其分为\(2\)个组,要求这两个组的平均值之和最大,组内的数不要求在原序列中连续。题目分析:我们......
  • CodeForces 1827E Bus Routes
    洛谷传送门CF传送门比较神奇的题。定一个非叶子\(r\)为根。显然只用判断两个叶子是否可达。求出每个叶子向上能一步跳到的深度最浅的点\(p_i\),那么如果\(p_i\)不在一条链上就无解,因为两条路径没有交点。然后只用判断\(p_i\)最深的叶子的\(p_i\)能不能一步到达其他......
  • Codeforces Gym 103119B - Boring Problem(高斯消元)
    考虑建出AC自动机,朴素做法是高斯消元,\(f_i=\sum\limits_{j=0}^{k-1}f_{to_{i,j}}p_j+1\),复杂度\(O(n^3m^3)\),不能接受。考虑优化高斯消元的过程,我们定义以下节点为“关键点”:根节点对于一个trie树(也就是未经过AC自动机getfail操作得到的树)上有超过两个儿子的节点\(x......
  • Codeforces Round 862 (Div. 2) A-D
    CodeforcesRound862(Div.2) A.WeNeedtheZerointa[N];voidsolve(){intn=read(),sum;for(inti=1;i<=n;i++){a[i]=read();if(i==1)sum=a[i];elsesum^=a[i];}if(n%2)cout<<sum<<'\n'......
  • Codeforces Round 874 (Div. 3) A-G
    比赛地址A.MusicalPuzzle题意:给出一个字符串,求有多少个不同的长度为2的子串Solution直接set存即可voidsolve(){ intn;cin>>n; strings;cin>>s; set<string>st; for(inti=0;i<n-1;i++) { st.insert(s.substr(i,2)); } cout<<st.size()<<"\n"......
  • Codeforces Round 874 (Div. 3)
    A.MusicalPuzzle题意:用最少的长度为2的字符串按一定规则拼出s。规则是:前一个字符串的尾与后一个字符串的首相同。分析:统计s中长度为2的不同字符串数量。代码:#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;constintN=1e5;intmain(){......
  • CodeForces1061C Multiplicity
    题面翻译从序列\(\{a_1,\a_2,\..\,\a_n\}\)中选出非空子序列\(\{b_1,\b_2,\..\,\b_k\}\),一个子序列合法需要满足\(\forall\i\in[1,\k],\i\|\b_i\)。求有多少互不相等的合法子序列,答案对\(10^9+7\)取模。序列\(\{1,\1\}\)有\(2\)种选法得到子序列\(......
  • Codeforces 874 div3 (A-G)
    Codeforces874div3A题意计算每两个相邻字符的不同种类B题意重排一个数组b,使得\(|a_i-b_i|\leqk\)思路根据相对大小去一一对应,这样每个位置的绝对值最小,数据保证有解代码voidsolve(){ cin>>n>>k; for(inti=1;i<=n;i++)cin>>a[i].first,a[i].second=i; for(in......
  • 【做题记录】CodeForces343D Water Tree
    题面翻译给出一棵以\(1\)为根节点的\(n\)个节点的有根树。每个点有一个权值,初始为\(0\)。\(m\)次操作。操作有\(3\)种:将点\(u\)和其子树上的所有节点的权值改为\(1\)。将点\(u\)到\(1\)的路径上的所有节点的权值改为\(0\)。询问点\(u\)的权值。\(1\le......
  • Codeforces 1832F - Zombies(wqs 二分)
    等价于最大化\(n\)对区间的交集之和。而对于每个\([l_i,r_i)\)我们肯定会选择与其交集最大的\([p,p+m)\)与之匹配,所以我们只用对\(k\)个区间进行决策即可。首先先发现一个东西:存在一种最优解,使得对于每个选择的区间\([p,p+m)\),要么有\(p=l_i\),要么有\(p+m=r_i\),也就是......