zoukankan      html  css  js  c++  java
  • XVI Open Cup named after E.V. Pankratiev. GP of SPB

    A. Bubbles

    枚举两个点,求出垂直平分线与$x$轴的交点,答案=交点数+1。

    时间复杂度$O(n^2log n)$。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const double eps=1e-9;
    int sgn(double x){
      if(x<-eps)return -1;
      if(x>eps)return 1;
      return 0;
    }
    
    struct P{
      double x,y;
      P(){x=y=0;}
      P(double _x,double _y){x=_x,y=_y;}
      P operator+(P v){return P(x+v.x,y+v.y);}
      P operator-(P v){return P(x-v.x,y-v.y);}
      P operator*(double v){return P(x*v,y*v);}
      P operator/(double v){return P(x/v,y/v);}
      P rot90(){return P(-y,x);}
    }a[2000];
    
    double q[1111111];
    
    double cross(P a,P b){return a.x*b.y-a.y*b.x;}
    
    int line_intersection(P a,P b,P p,P q,P&o){
      if(!sgn(a.x-b.x)&&!sgn(a.y-b.y))return 0;
      if(!sgn(p.x-q.x)&&!sgn(p.y-q.y))return 0;  
      double U=cross(p-a,q-p),
             D=cross(b-a,q-p);
      if(sgn(D)==0)return 0;
      o=a+(b-a)*(U/D);
      return 1;
    }
    
    int main () {
      freopen ( "bubbles.in" , "r" , stdin ) ;
      freopen ( "bubbles.out" , "w" , stdout ) ;
      int n;
      scanf("%d",&n);
      for(int i=1;i<=n;i++){
        scanf("%lf%lf",&a[i].x,&a[i].y);
      }
      P A(-100,0),B(100,0);
      int cnt=0;
      for(int i=1;i<=n;i++)for(int j=1;j<i;j++){
        P t=(a[i]+a[j])/2.0;
        P v=a[i]-a[j];
        v=v.rot90();
        P tmp;
        if(line_intersection(t,t+v,A,B,tmp)){
          q[++cnt]=tmp.x;
        }
      }
      sort(q+1,q+cnt+1);
      int ans=1;
      for(int i=1;i<=cnt;i++)if(i==1||sgn(q[i]-q[i-1]))ans++;
      printf("%d",ans);
      return 0;
    }
    

      

    B. Drop7

    留坑。

    C. Eulerian Graphs

    留坑。

    D. At Least Half

    枚举所有质数$p$,找出所有$p$的倍数,设$s[i]$表示前$i$个数里$p$的倍数$ imes2$,枚举$i$,要找到最小的$j$满足$s[i]-igeq s[j]-j$,维护$s[i]-i$的前缀最小值,然后二分查找即可。找到$j$之后贪心计算往左往右能扩展多少。

    时间复杂度$O(nlog nloglog n)$。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int>pi;
    const int Maxn=1000020;
    int a[Maxn];
    vector<int>V[Maxn/10];
    vector<int>pri;
    int n;
    bool isp[Maxn];
    void getp(){
    	for(int i=2;i<Maxn;i++){
    		if(!isp[i]){
    			pri.push_back(i);
    		}
    		for(int j=0;j<pri.size();j++){
    			if(i*pri[j]>=Maxn)break;
    			isp[i*pri[j]]=1;
    			if(i%pri[j]==0)break;
    		}
    	}
    }
    int ans,ansr;
    int g[Maxn],gmx[Maxn];
    void check(vector<int>&V){
    	//for(int i=0;i<V.size();i++)printf("%d ",V[i]);puts("");
    	for(int i=0;i<V.size();i++)g[i]=V[i]-2*(i+1);
    	for(int i=0;i<V.size();i++)gmx[i]=V[i]-1-2*(i);
    	for(int i=1;i<V.size();i++)gmx[i]=max(gmx[i],gmx[i-1]);
    	for(int i=0;i<V.size();i++){
    		int j=lower_bound(gmx,gmx+V.size(),g[i])-gmx;
    		int has=i-j+1,haslen=V[i]-V[j]+1;
    		//printf("val=1%d val2=%d
    ",V[i-1],j);
    		int rr=i==V.size()-1?n:(V[i+1]-1);
    		int ll=j==0?1:(V[j-1]+1);
    		int tmpans=min(rr-ll+1,has*2);
    		int csr=V[i]+min(tmpans-haslen,rr-V[i]);
    		//printf("%d %d %d %d
    ",ll,rr,has,tmpans);
    		if(tmpans>ans){
    			ans=tmpans;
    			ansr=csr;
    		}
    	}
    }
    void solve(vector<int>&V){
    	check(V);
    }
    int main()
    {
    freopen("halfgcd.in","r",stdin);
    freopen("halfgcd.out","w",stdout);
    	getp();
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d",a+i);
    	for(int i=1;i<=n;i++){
    		int x=a[i];
    		for(int j=0;j<pri.size();j++){
    			if(1LL*pri[j]*pri[j]>x)break;
    			if(x%pri[j])continue;
    			V[j].push_back(i);
    			while(x%pri[j]==0)x/=pri[j];
    		}
    		if(x>1)V[lower_bound(pri.begin(),pri.end(),x)-pri.begin()].push_back(i);
    	}
    	ans=0,ansr=-1;
    	for(int it=0;it<pri.size();it++){
    		if(!V[it].size())continue;
    		solve(V[it]);
    	}
    	if(!ans){
    		puts("0 0");
    	}
    	else printf("%d %d
    ",ansr-ans+1,ansr);
    	return 0;
    }
    

      

    E. Next Partition in RLE Notation

    只有最后几个数是有用的,分类讨论构造即可。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef long long LL ;
    typedef pair < int , int > pii ;
    typedef pair < LL , LL > pll ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    
    const int MAXN = 100005 ;
    
    vector < pll > G ;
    int n ;
    
    void get ( LL N , LL K , LL val ) {
    	LL tmp1 = ( N - K ) / ( val - 1 ) ;
    	LL tmp2 = ( N - K ) % ( val - 1 ) ;
    	LL tmp3 = K - tmp1 - ( tmp2 > 0 ) ;
    	if ( tmp1 ) G.push_back ( pll ( tmp1 , val ) ) ;
    	if ( tmp2 ) G.push_back ( pll ( 1 , tmp2 + 1 ) ) ;
    	if ( tmp3 ) G.push_back ( pll ( tmp3 , 1 ) ) ;
    }
    
    void solve () {
    	G.clear () ;
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		LL x , y ;
    		scanf ( "%lld%lld" , &x , &y ) ;
    		G.push_back ( pll ( x , y ) ) ;
    	}
    	if ( n == 1 || n == 2 && G[0].second - G[1].second == 1 ) {
    		printf ( "-1
    " ) ;
    		return ;
    	}
    	pll a = G[n - 1] ;
    	-- n ;
    	G.pop_back () ;
    	pll b = G[n - 1] ;
    	if ( G[n - 1].second - a.second > 1 ) {
    		G[n - 1].first -- ;
    		if ( !G[n - 1].first ) {
    			G.pop_back () ;
    			-- n ;
    		}
    		//printf ( "%lld %lld %lld %lld
    " , a.first , a.second , b.first , b.second ) ;
    		get ( a.first * a.second + b.second , a.first + 1 , b.second - 1 ) ;
    	} else {
    		G.pop_back () ;
    		-- n ;
    		pll c = G[n - 1] ;
    		G[n - 1].first -- ;
    		if ( !G[n - 1].first ) {
    			G.pop_back () ;
    			-- n ;
    		}
    		get ( a.first * a.second + b.first * b.second + c.second , a.first + b.first + 1 , c.second - 1 ) ;
    	}
    	printf ( "%d
    " , ( int ) G.size () ) ;
    	for ( int i = 0 ; i < G.size () ; ++ i ) {
    		printf ( "%lld %lld
    " , G[i].first , G[i].second ) ;
    	}
    }
    
    int main () {
    	freopen ( "next-partition-rle.in" , "r" , stdin ) ;
    	freopen ( "next-partition-rle.out" , "w" , stdout ) ;
    	while ( ~scanf ( "%d" , &n ) ) solve () ;
    	return 0 ;
    }
    

      

    F. Equation

    留坑。

    G. “Swap-Plus” Puzzle

    显然存在一种最优操作序列,先做行交换,在做列交换,最后再交换格子。

    枚举行交换、列交换的顺序,然后贪心交换即可。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<iostream>
    using namespace std;
    
    
    int i,j,a[9][9],b[9],c[9],d[9][9],m,e[100];
    int ans=~0U>>1,cnt;
    
    
    string q[100];
    
    int now;
    
    
    int cal(int*a,int n){
      int t=0;
      int i,j;
      static int b[100];
      for(i=1;i<=n;i++)b[i]=a[i];
      for(i=1;i<=n;i++){
        for(j=1;j<=n;j++)if(b[j]==i){
          if(i!=j)t++;
          swap(b[j],b[i]);
          break;
        }
      }
      return t;
    }
    
    int cal2(int*a,int n){
      int t=0;
      int i,j;
      static int b[100];
      for(i=1;i<=n;i++)b[i]=i;
      for(i=1;i<=n;i++){
        for(j=1;j<=n;j++)if(b[j]==a[i]){
          if(i!=j)t++;
          swap(b[j],b[i]);
          break;
        }
      }
      return t;
    }
    
    void conb(int*a,char st){//[1,2,3,4]->a
      static int b[10];
      int i,j;
      for(i=1;i<=4;i++)b[i]=i;
      for(i=1;i<=4;i++){
        for(j=1;j<=4;j++)if(b[j]==a[i]){
          if(i!=j){
            string t="";
            t.push_back(b[i]+st-1);
            t.push_back('-');
            t.push_back(b[j]+st-1);
            q[++cnt]=t;
          }
          swap(b[j],b[i]);
          break;
        }
      }
    }
    void cond(){//a->[1,2,3,4,...,16]
      static int a[9][9];
      int i,j,x,y;
      for(i=1;i<=4;i++)for(j=1;j<=4;j++)a[i][j]=d[i][j];
      for(i=1;i<=4;i++)for(j=1;j<=4;j++){
        int now=(i-1)*4+j;
        if(a[i][j]==now)continue;
        bool flag=0;
        for(x=1;x<=4;x++){
          for(y=1;y<=4;y++)if(a[x][y]==now){
            flag=1;
            swap(a[x][y],a[i][j]);
            string t="";
            t.push_back(i+'a'-1);
            t.push_back(j+'0');
            t.push_back('-');
            t.push_back(x+'a'-1);
            t.push_back(y+'0');
            q[++cnt]=t;
            break;
          }
          if(flag)break;
        }
      }
    }
    
    
    int main (){
      freopen ( "puzzle-swap-plus.in" , "r" , stdin ) ;
      freopen ( "puzzle-swap-plus.out" , "w" , stdout ) ;
      for(i=1;i<=4;i++)
        for(j=1;j<=4;j++)
          scanf("%d",&a[i][j]);
      for(i=1;i<=4;i++)b[i]=i;
      
      do{
        for(i=1;i<=4;i++)c[i]=i;
        do{
          now=cal2(b,4)+cal2(c,4);
          for(i=1;i<=4;i++)for(j=1;j<=4;j++)d[b[i]][c[j]]=a[i][j];
          m=0;
          for(i=1;i<=4;i++)for(j=1;j<=4;j++)e[++m]=d[i][j];
          now+=cal(e,16);
          if(now<ans){
            ans=now;
            cnt=0;
            conb(b,'a');
            conb(c,'1');
            cond();
          }
        }while(next_permutation(c+1,c+4+1));
      }while(next_permutation(b+1,b+4+1));
      printf("%d
    ",ans);
      for(i=1;i<=cnt;i++)cout<<q[i]<<endl;
      return 0;
    }
    

      

    H. Wrong Sieve

    考虑每一轮与上一轮位置的递推关系即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int Maxn=105;
    typedef long long LL;
    typedef pair<int,int>pi;
    LL solve(LL x){
    	for(LL i=1;x>=(i+1);i++){
    		if(x%(i+1)==0)return -1;
    		x=x-x/(i+1);
    	}
    	return x;
    }
    int main()
    {
    freopen("sieve.in","r",stdin);
    freopen("sieve.out","w",stdout);
    	int _;scanf("%d",&_);
    	while(_--){
    		LL x;scanf("%lld",&x);
    		LL ans=solve(x);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

      

    I. Space Cat

    DP,$f[i][j]$表示在第$i$条线段,重心方向为$j$的最小代价,注意要特判图不联通的情况。

    时间复杂度$O(n)$。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef pair < int , int > pii ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    
    typedef long long ll;
    const ll inf=1LL<<60;
    const int N=100010;
    
    int n,i,a[N],b[N],c[N];
    ll f[N][2];
    
    inline void up(ll&x,ll y){if(x>y)x=y;}
    
    
    int main () {
    	int T ;
    	freopen ( "space-cat.in" , "r" , stdin ) ;
    	freopen ( "space-cat.out" , "w" , stdout ) ;
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)scanf("%d",&a[i]);
    	for(i=1;i<=n;i++)scanf("%d",&b[i]),c[i]=a[i]-b[i];
    	for(i=2;i<=n;i++)if(b[i]>=a[i-1]||b[i-1]>=a[i])return puts("-1"),0;
    	for(i=1;i<=n;i++)f[i][0]=f[i][1]=inf;
    	f[1][0]=0;
    	for(i=1;i<=n;i++){
    	  if(i>1){
    	    if(a[i-1]<=a[i])up(f[i][1],f[i-1][1]);
    	    if(b[i-1]>=b[i])up(f[i][0],f[i-1][0]);
              }
              for(int j=0;j<4;j++){
                up(f[i][0],f[i][1]+c[i]);
                up(f[i][1],f[i][0]+c[i]);
              }
    	}
    	if(f[n][0]>=inf)f[n][0]=-1;
    	printf("%lld
    ",f[n][0]);
    	return 0 ;
    }
    

      

    J. Tic-Tac-Toe Variation

    第一步填中间,然后只有两种情况,分类讨论构造策略即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int>pi;
    const int Maxn=1000020;
    char Mp[4][4];
    bool getMp(){
    	bool ret=0;
    	for(int i=0;i<3;i++){
    		scanf("%s",Mp[i]);
    		for(int j=0;j<3;j++){
    			if(Mp[i][j]!='x')ret=1;
    		}
    	}
    	return ret;
    }
    int idx[3][3]={
    	{0,1,2},
    	{7,-1,3},
    	{6,5,4}
    };
    int dx[8],dy[8];
    int curMp[3][3];
    int cg(char c){
    	if(c=='.')return 0;
    	if(c=='x')return 1;
    	return 2;
    }
    void tran(){
    	for(int i=0;i<3;i++){
    		for(int j=0;j<3;j++){
    			curMp[i][j]=cg(Mp[i][j]);
    		}
    	}
    }
    void pt(){
    	for(int i=0;i<3;i++){
    		for(int j=0;j<3;j++){
    			int c=curMp[i][j];
    			if(!c)putchar('.');
    			if(c==1)putchar('x');
    			if(c==2)putchar('o');
    		}
    		puts("");
    	}
    	fflush(stdout);
    }
    int getst(){
    	for(int i=0;i<3;i++){
    		for(int j=0;j<3;j++){
    			if(curMp[i][j]==2){
    				return idx[i][j];
    			}
    		}
    	}
    }
    int main()
    {
    //freopen("halfgcd.in","r",stdin);
    //freopen("halfgcd.out","w",stdout);
    	for(int i=0;i<3;i++){
    		for(int j=0;j<3;j++){
    			if(i==1&&j==1)continue;
    			dx[idx[i][j]]=i;
    			dy[idx[i][j]]=j;
    		}
    	}
    	while(getMp()){
    		int st;
    		memset(curMp,0,sizeof curMp);
    		for(int it=0;;it++){
    			if(it==0){
    				curMp[1][1]=1;
    				pt();
    				continue;
    			}
    			if(it==1){
    				getMp();
    				tran();
    				st=getst();
    				int nst=(st+2)%8;
    				curMp[dx[nst]][dy[nst]]=1;
    				pt();
    				continue;
    			}
    			if(it==2){
    				getMp();
    				tran();
    				if(curMp[dx[(st+6)%8]][dy[(st+6)%8]]!=2){
    					curMp[dx[(st+6)%8]][dy[(st+6)%8]]=1;
    					pt();
    					break;
    				}
    				else{
    					curMp[dx[(st+3)%8]][dy[(st+3)%8]]=1;
    					pt();
    				}
    			}
    			if(it==3){
    				getMp();
    				tran();
    				int nst=st&1?((st+1)%8):((st+4)%8);
    				if(!curMp[dx[nst]][dy[nst]]){
    					curMp[dx[nst]][dy[nst]]=1;
    					pt();
    					break;
    				}
    				else{
    					nst=(st+7)%8;
    					curMp[dx[nst]][dy[nst]]=1;
    					pt();
    					break;
    				}
    			}
    		}
    	}
    	return 0;
    }
    

      

    K. Captain Tarjan

    对于每个询问,将路径上的边权都加1。

    那么问题就变成了,给定一棵树,找到一个点,然后随意剖分,使得所有轻边的权值和最小,两遍DP即可。

    时间复杂度$O(mlog n)$。

    #include <bits/stdc++.h>
    using namespace std ;
    
    typedef long long LL ;
    typedef pair < int , int > pii ;
    
    #define clr( a , x ) memset ( a , x , sizeof a )
    
    const int MAXN = 100005 ;
    
    vector < pii > G[MAXN] ;
    LL dp[MAXN] , dp2[MAXN] , maxc[MAXN] ;
    LL Ldp[MAXN] , Rdp[MAXN] , Lmaxc[MAXN] , Rmaxc[MAXN] ;
    int c[MAXN] ;
    int siz[MAXN] ;
    int son[MAXN] ;
    int pre[MAXN] ;
    int top[MAXN] ;
    int dep[MAXN] ;
    int n , m ;
    LL ans ;
    
    void predfs ( int u , int f ) {
    	siz[u] = 1 ;
    	son[u] = 0 ;
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i].first ;
    		if ( v == f ) continue ;
    		pre[v] = u ;
    		dep[v] = dep[u] + 1 ;
    		predfs ( v , u ) ;
    		siz[u] += siz[v] ;
    		if ( siz[v] > siz[son[u]] ) son[u] = v ;
    	}
    }
    
    void rebuild ( int u , int top_element ) {
    	top[u] = top_element ;
    	if ( son[u] ) rebuild ( son[u] , top_element ) ;
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i].first ;
    		if ( v != pre[u] && v != son[u] ) rebuild ( v , v ) ;
    	}
    }
    
    int get_lca ( int x , int y ) {
    	while ( top[x] != top[y] ) {
    		if ( dep[top[x]] > dep[top[y]] ) x = pre[top[x]] ;
    		else y = pre[top[y]] ;
    	}
    	return dep[x] < dep[y] ? x : y ;
    }
    
    void dfs1 ( int u ) {
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i].first ;
    		if ( v == pre[u] ) continue ;
    		dfs1 ( v ) ;
    		G[u][i].second = c[v] ;
    		c[u] += c[v] ;
    	}
    }
    
    void dfs2 ( int u ) {
    	dp[u] = maxc[u] = 0 ;
    	for ( int i = 0 ; i < G[u].size () ; ++ i ) {
    		int v = G[u][i].first ;
    		if ( v == pre[u] ) continue ;
    		dfs2 ( v ) ;
    		dp[u] += dp[v] + G[u][i].second ;
    		maxc[u] = max ( maxc[u] , G[u][i].second + 0LL ) ;
    	}
    	dp[u] -= maxc[u] ;
    }
    
    void dfs3 ( int u , int cost ) {
    	int n = G[u].size () ;
    	Ldp[0] = 0 ;
    	Rdp[n - 1] = 0 ;
    	Lmaxc[0] = 0 ;
    	Rmaxc[n - 1] = 0 ;
    	for ( int i = 1 ; i < n ; ++ i ) {
    		int v = G[u][i - 1].first ;
    		if ( v == pre[u] ) {
    			Ldp[i] = Ldp[i - 1] ;
    			Lmaxc[i] = Lmaxc[i - 1] ;
    		} else {
    			Ldp[i] = Ldp[i - 1] + dp[v] + G[u][i - 1].second ;
    			Lmaxc[i] = max ( Lmaxc[i - 1] , G[u][i - 1].second + 0LL ) ;
    		}
    	}
    	for ( int i = n - 2 ; i >= 0 ; -- i ) {
    		int v = G[u][i + 1].first ;
    		if ( v == pre[u] ) {
    			Rdp[i] = Rdp[i + 1] ;
    			Rmaxc[i] = Rmaxc[i + 1] ;
    		} else {
    			Rdp[i] = Rdp[i + 1] + dp[v] + G[u][i + 1].second ;
    			Rmaxc[i] = max ( Rmaxc[i + 1] , G[u][i + 1].second + 0LL ) ;
    		}
    	}
    	for ( int i = 0 ; i < n ; ++ i ) {
    		int v = G[u][i].first ;
    		if ( v == pre[u] ) continue ;
    		dp2[v] = dp2[u] + Ldp[i] + Rdp[i] + cost - max ( max ( Lmaxc[i] , Rmaxc[i] ) , cost + 0LL ) ;
    		ans = min ( ans , dp2[v] + dp[v] + maxc[v] + G[u][i].second - max ( maxc[v] , 0LL + G[u][i].second ) ) ;
    	}
    	for ( int i = 0 ; i < n ; ++ i ) {
    		int v = G[u][i].first ;
    		if ( v == pre[u] ) continue ;
    		dfs3 ( v , G[u][i].second ) ;
    	}
    }
    
    void solve () {
    	for ( int i = 1 ; i <= n ; ++ i ) {
    		G[i].clear () ;
    		c[i] = 0 ;
    	}
    	for ( int i = 1 ; i < n ; ++ i ) {
    		int u , v ;
    		scanf ( "%d%d" , &u , &v ) ;
    		G[u].push_back ( pii ( v , 0 ) ) ;
    		G[v].push_back ( pii ( u , 0 ) ) ;
    	}
    	predfs ( 1 , 1 ) ;
    	rebuild ( 1 , 1 ) ;
    	for ( int i = 0 ; i < m ; ++ i ) {
    		int u , v ;
    		scanf ( "%d%d" , &u , &v ) ;
    		c[u] ++ ;
    		c[v] ++ ;
    		int lca = get_lca ( u , v ) ;
    		c[lca] -= 2 ;
    	}
    	dp2[1] = 0 ;
    	dfs1 ( 1 ) ;
    	dfs2 ( 1 ) ;
    	ans = dp[1] ;
    	dfs3 ( 1 , 0 ) ;
    	printf ( "%lld
    " , ans ) ;
    }
    
    int main () {
    	freopen ( "treepaths.in" , "r" , stdin ) ;
    	freopen ( "treepaths.out" , "w" , stdout ) ;
    	while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ;
    	return 0 ;
    }
    

      

    L. Gardening Lesson

    求出两棵树的重心,枚举重心作为根,然后求出每棵子树的Hash值,在两棵树上一起dfs即可。

    时间复杂度$O(nlog n)$。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int>pi;
    const int Maxn = 100005 , x = 123 , M = 998244353 , Left = 23 , Right = 371 ;
    const int Hleaf=Left*Right,Inf=1e9;
    vector < int > G1[Maxn] , G2[Maxn] ;
    int H1[Maxn] , H2[Maxn] ;
    int sz[Maxn],sonsz[Maxn],ans ;
    void dfs(int u , vector<int>*G,int p){
    	sz[u]= 1;
    	sonsz[u]=0;
    	for(int i=0;i<G[u].size ();++i){
    		int v =G[u][i];
    		if(v==p)continue ;
    		dfs(v,G,u);
    		sz[u]+=sz[v];
    		if(sz[v]>sonsz[u])sonsz[u]=sz[v];
    	}
    }
    vector<int>getroot(vector<int>*G,int n){
    	dfs(1,G,0);
    	vector<int>ret;
    	for(int i=1;i<=n;++i){
    		if(max(n-sz[i],sonsz[i])<=n/2){
    			ret.push_back(i);
    		}
    	}
    	return ret;
    }
    bool cmp1(int a, int b){return H1[a]<H1[b];}
    bool cmp2(int a, int b){return H2[a]<H2[b];}
    void dfs2(int u,int p,vector<int>*G,int*H,int ty){
    	H[u]=Left;
    	for(int i =0;i<G[u].size();++i){
    		int v=G[u][i];if(v==p)continue;
    		dfs2(v,u,G,H,ty);
    	}
    	sort(G[u].begin(),G[u].end(),ty==1?cmp1:cmp2);
    	for(int i=0;i<G[u].size();++i){
    		int v=G[u][i];if(v==p)continue;
    		H[u]=((1LL*H[u]*x)^H[v])%M;
    	}
    	H[u]=1LL*H[u]*Right%M;
    }
    void check(int ua,int pa,int ub,int pb){
    	//printf("%d %d %d %d
    ",ua,pa,ub,pb);
    	set<pi>S;
    	for(int i=0;i<G2[ub].size();i++){
    		int v=G2[ub][i];
    		if(v==pb)continue;
    		S.insert(pi(H2[v],v));
    	}
    	vector<int>rest;
    	for(int i=0;i<G1[ua].size();i++){
    		int v=G1[ua][i];
    		if(v==pa)continue;
    		set<pi>::iterator it=S.lower_bound(pi(H1[v],-1));
    		if(it==S.end()||(it->first!=H1[v]))rest.push_back(v);
    		else S.erase(it);
    	}
    	if(rest.size()>1||S.size()>1)return;
    	if(S.size()==1&&!rest.size()){
    		if(S.begin()->first!=Hleaf)return;
    		for(int i=0;i<G2[ub].size();i++){
    			int v=G2[ub][i];if(v==pb)continue;
    			if(H2[v]==Hleaf){ans=min(ans,v);}
    		}
    		return;
    	}
    	if(S.size()==1&&rest.size()==1){
    		for(int i=0;i<G2[ub].size();i++){
    			int v=G2[ub][i];if(v==pb)continue;
    			if(H2[v]==S.begin()->first)check(rest[0],ua,v,ub);
    		}
    	}
    }
    void solve( int rt1 , int rt2){
    	dfs2(rt1,0,G1,H1,1);
    	dfs2(rt2,0,G2,H2,2);
    	check(rt1,0,rt2,0);
    }
    void pt(vector<int>&v){
    	for(int i=0;i<v.size();i++)printf("%d ",v[i]);
    	puts("");
    }
    int main()
    {
    freopen("unexpected-leaf.in","r",stdin);
    freopen("unexpected-leaf.out","w",stdout);
    	int n;
    	while(scanf("%d",&n)!=EOF){
    		for(int i=1;i<=n+1;i++){
    			G1[i].clear();
    			G2[i].clear();
    		}
    		for(int i=1;i<n;i++){
    			int u,v;scanf("%d%d",&u,&v);
    			G1[u].push_back(v);
    			G1[v].push_back(u);
    		}
    		for(int i=1;i<=n;i++){
    			int u,v;scanf("%d%d",&u,&v);
    			G2[u].push_back(v);
    			G2[v].push_back(u);
    		}
    		if(n==1){
    			printf("1
    ");
    			continue;
    		}
    		if(n==2){
    			if(G2[1].size()==2)printf("2
    ");
    			else printf("1
    ");
    			continue;
    		}
    		vector<int>tmp1=getroot(G1,n);
    		vector<int>tmp2=getroot(G2,n+1);
    		//pt(tmp1);
    		//pt(tmp2);
    		ans=Inf;
    		//solve(1,3);
    		for(int i=0;i<tmp1.size();i++){
    			for(int j=0;j<tmp2.size();j++){
    				solve(tmp1[i],tmp2[j]);
    			}
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

      


    总结:

    • L题发现树同构模板有误。
  • 相关阅读:
    暂存
    近期学习规划
    将博客搬至CSDN
    后缀自动机五·重复旋律8
    后缀自动机四·重复旋律7
    拓扑排序
    后缀自动机三·重复旋律6
    后缀自动机二·重复旋律5
    交错和(数位dp)
    博弈专题
  • 原文地址:https://www.cnblogs.com/clrs97/p/6032092.html
Copyright © 2011-2022 走看看