zoukankan      html  css  js  c++  java
  • CF1439E. Cheat and Win

    题目大意

    一个从0开始的网格图,只有x&y=0的格子(x,y)存在,显然构成以一棵树

    设根为(0,0),初始有一些黑色格子(给出的若干条路径并),A先手,之后AB轮流操作,每次可以把一个黑色格子变白,同时把所有祖先任意变色(各自独立),不能操作者输

    现在B想要作弊,每次可以在开始前选一个点把其到根的路径反色,求B获胜的最小操作次数

    n<=1e5,x,y<=1e9

    题解

    ll:简单题

    首先考虑判定,可以发现先把所有格子按x+y分类后,只和每个的奇偶性有关

    因为如果A操作了某个格子同时改变了祖先奇偶性,则B也可以操作将其还原

    所以等价于一行格子,答案显然就是段数

    也可以直接考虑sg,因为sg是异或所以反色等于加1,那么一个点(x,y)的sg就是2^(x+y),因为可以到达0~2^(x+y)-1

    于是变成了求路径并,建虚树即可

    注意实现,求lca可以每次将平面四分,根据两个点的位置来算,排序就求相对dfs序,先父亲后儿子,如果没有祖先关系就用求lca的方法来分治判断

    时间O(nlog^2)

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define p(a,b) pair<int,int>(a,b)
    #define max(a,b) (a>b?a:b)
    #define min(a,b) (a<b?a:b)
    #define ll long long
    //#define file
    using namespace std;
    
    struct type{int x,y,fx,fy;} b[100001][2],c[200001],d[400001],A[400001],D[400001],Lca;
    int p[30],a[400001][3],ls[400001],fa[400001],f[400001],g[400001],dp[400001];
    int T,n,N,i,j,k,l,t,len,tot,mn,rt,ans;
    map<pair<int,int>,int> mp;
    map<int,int> mp2;
    
    void look()
    {
    	fo(i,0,50)
    	{
    		fo(j,0,50)
    		cout<<((i&j)==0);
    		cout<<endl;
    	}
    }
    
    void swap(type &a,type &b) {type c=a;a=b;b=c;}
    void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
    type lca(type a,type b)
    {
    	int i,j,x=0,y=0,X1,Y1,X2,Y2,s1,s2;
    	fd(i,29,0)
    	{
    		X1=(a.x&p[i])>0,Y1=(a.y&p[i])>0;
    		X2=(b.x&p[i])>0,Y2=(b.y&p[i])>0;
    		if (X1) s1=1; else if (!Y1) s1=2; else s1=3;
    		if (X2) s2=1; else if (!Y2) s2=2; else s2=3;
    		if (s1>s2) j=s1,s1=s2,s2=j,swap(a,b);
    		
    		if (s1==1 && s2==1) x+=p[i],a.x-=p[i],b.x-=p[i]; else
    		if (s1==3 && s2==3) y+=p[i],a.y-=p[i],b.y-=p[i]; else
    		{
    			if (s1==1) a.x=p[i]-1,a.y=0;
    			if (s2==3) b.y=p[i]-1,b.x=0;
    		}
    	}
    	return type{x,y};
    }
    bool cmp(type a,type b)
    {
    	type Lca=lca(a,b);
    	int i,X1,Y1,X2,Y2,s1,s2;
    	if (a.x==b.x && a.y==b.y) return 0;
    	if (Lca.x==a.x && Lca.y==a.y) return 1;
    	if (Lca.x==b.x && Lca.y==b.y) return 0;
    	
    	fd(i,29,0)
    	{
    		X1=(a.x&p[i])>0,Y1=(a.y&p[i])>0;
    		X2=(b.x&p[i])>0,Y2=(b.y&p[i])>0;
    		if (X1) s1=1; else if (!Y1) s1=2; else s1=3;
    		if (X2) s2=1; else if (!Y2) s2=2; else s2=3;
    		if (s1!=s2) return s1<s2;
    		if (s1==1 && s2==1) a.x-=p[i],b.x-=p[i];
    		if (s1==3 && s2==3) a.y-=p[i],b.y-=p[i];
    	}
    	return 0;
    }
    
    void build()
    {
    	type Lca,s;
    	sort(c+1,c+N+1,cmp);
    	t=1,d[1]=c[1];
    	fo(i,2,N)
    	{
    		Lca=lca(d[t],c[i]),l=0;
    		while (t && Lca.x+Lca.y<d[t].x+d[t].y)
    		D[++l]=d[t--];
    		
    		if (l)
    		{
    			fo(j,1,l-1) D[j].fx=D[j+1].x,D[j].fy=D[j+1].y;
    			D[l].fx=Lca.x,D[l].fy=Lca.y;
    			while (l) A[++tot]=D[l--];
    		}
    		if (!t || Lca.x+Lca.y>d[t].x+d[t].y) d[++t]=Lca;
    		if (Lca.x+Lca.y<c[i].x+c[i].y) d[++t]=c[i];
    	}
    	if (t)
    	{
    		fd(j,t,1) d[j].fx=d[j-1].x,d[j].fy=d[j-1].y;
    		while (t) A[++tot]=d[t--];
    	}
    	
    	mn=2000000000;
    	fo(i,1,tot) mp[p(A[i].x,A[i].y)]=i,mn=min(mn,A[i].x+A[i].y);
    	fo(i,1,tot)
    	if (A[i].x+A[i].y>mn)
    	{
    		j=mp[p(A[i].x,A[i].y)];
    		k=mp[p(A[i].fx,A[i].fy)];
    		New(k,j);
    	}
    	else rt=i;
    }
    
    void change(int x,int y)
    {
    	int s,s2;--x;
    	if (x>=0)
    	s=mp2[x],s2=s^1,ans+=s2-s,mp2[x]=s2;
    	s=mp2[y],s2=s^1,ans+=s2-s,mp2[y]=s2;
    }
    
    void Dfs(int Fa,int t)
    {
    	int i;
    	dp[t]=A[t].x+A[t].y,fa[t]=Fa;
    	for (i=ls[t]; i; i=a[i][1]) if (a[i][0]!=Fa) Dfs(t,a[i][0]);
    }
    void dfs(int Fa,int t)
    {
    	int i;
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	{
    		dfs(t,a[i][0]),f[t]+=f[a[i][0]],g[t]+=g[a[i][0]];
    		if (g[a[i][0]] && dp[t]+1<dp[a[i][0]])
    		change(dp[t]+1,dp[a[i][0]]-1);
    	}
    	if (f[t]) change(dp[t],dp[t]);
    }
    
    int main()
    {
    	#ifdef file
    	freopen("CF1439E.in","r",stdin);
    	#endif
    	
    	p[0]=1;
    	fo(i,1,29) p[i]=p[i-1]*2;
    	
    	scanf("%d",&n),N=n*2;
    	fo(i,1,n) scanf("%d%d%d%d",&b[i][0].x,&b[i][0].y,&b[i][1].x,&b[i][1].y),c[i*2-1]=b[i][0],c[i*2]=b[i][1];
    	
    	build();
    	Dfs(0,rt);
    	fo(i,1,n)
    	{
    		if (b[i][0].x+b[i][0].y>b[i][1].x+b[i][1].y) swap(b[i][0],b[i][1]);
    		Lca=lca(b[i][0],b[i][1]);
    		
    		if (b[i][0].x==b[i][1].x && b[i][0].y==b[i][1].y)
    		{
    			j=mp[p(b[i][0].x,b[i][0].y)];
    			++f[j],--f[fa[j]];
    		}
    		else
    		if (b[i][0].x==Lca.x && b[i][0].y==Lca.y)
    		{
    			j=mp[p(b[i][0].x,b[i][0].y)];
    			k=mp[p(b[i][1].x,b[i][1].y)];
    			++f[k],--f[fa[j]];
    			++g[k],--g[j];
    		}
    		else
    		{
    			j=mp[p(b[i][0].x,b[i][0].y)];
    			k=mp[p(b[i][1].x,b[i][1].y)];
    			l=mp[p(Lca.x,Lca.y)];
    			++f[j],++f[k],--f[l],--f[fa[l]];
    			++g[j],++g[k],g[l]-=2;
    		}
    	}
    	dfs(0,rt);
    	printf("%d
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    requests
    Unit5 Going places
    Unit1 A time to remember
    SQL:找到一个关于all some any的用法,可在SSMS里看效果
    SQL join小结
    mac 配置tomcat
    oc与java c++语法区别
    swift调用oc项目
    java网络编程之socket
    windows远程控制mac
  • 原文地址:https://www.cnblogs.com/gmh77/p/14001527.html
Copyright © 2011-2022 走看看