zoukankan      html  css  js  c++  java
  • CF1444E. Finding the Vertex

    题目描述

    题解

    设每条边都有一个初始为0的边权,每次查询断成两个块后就把两个块的边权+1,最后得到的树上任意两条边权相同的边之间都有一条边权小于其的边,则操作次数为最小边+1

    把边权反过来,即初始为k每次把两侧-1,则变为相同的之间有大于其的

    考虑dp,设f[i]表示以i为根的子树中能连上来的边的集合,用一个n位二进制数存,则显然是让f越小越好

    加上x到儿子y的权值为i的边之后,f[y]的第i位首先要为0,加上后变成1同时0~i-1位变成0,因为已经有大于其的边了所以失去限制

    因为边权必须要有,所以问题变成了已知a1,a2,...an,求b1,b2,...bn满足bi>ai且b1&b2&...&bn=0,使b1|b2|...|bn最小

    把a+1后按位确定,如果当前位有1则可以把一个最高位为当前位且为1的a消掉该位丢回去,如果不存在或者消成0了则可以完全消掉,如果有>1个则无解

    一共要做n^2次,所以时间复杂度O(n^3log),最后询问当前块最大边即可

    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 ll long long
    //#define file
    using namespace std;
    
    struct type{ll s1,s2;int id;} b[101],s,Inf;
    int a[202][3],ls[101],fa[101],id[101],D[101],f[202],F[202],d[202],n,i,j,k,l,len,x,y,z,mx,mx2,t;
    bool bz[101];
    ll p[51];
    bool operator < (type a,type b) {return !(a.s1>b.s1 || a.s1==b.s1 && a.s2>b.s2);}
    priority_queue<type> hp;
    ifstream f1;
    
    void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
    type Xor(type s,int t) {return (t<50)?type{s.s1,s.s2^p[t],s.id}:type{s.s1^p[t-50],s.s2,s.id};}
    bool Zero(type s) {return !s.s1 && !s.s2;}
    type Add(type a) {++a.s2; if (a.s2>=p[50]) a.s2-=p[50],++a.s1;return a;}
    bool Get(type s,int t) {return (t<50)?((s.s2&p[t])>0):((s.s1&p[t-50])>0);}
    bool pd(type a)
    {
    	int i,j,k,l;
    	t=0;
    	fd(i,n-1,0)
    	if (Get(a,i))
    	{
    		if (hp.empty()) {fo(i,1,t) f[d[i]]=F[d[i]];return 1;}
    		s=hp.top(),hp.pop();
    		if (Get(s,i+1)) return 0;
    		if (Get(s,i))
    		{
    			if (!Zero(Xor(s,i))) hp.push(Xor(s,i));
    			else F[s.id]=i,d[++t]=s.id;
    		}
    		else F[s.id]=i,d[++t]=s.id;
    	}
    	else
    	if (!hp.empty())
    	{
    		s=hp.top();
    		if (Get(s,i)) return 0;
    	}
    	
    	if (hp.empty()) {fo(i,1,t) f[d[i]]=F[d[i]];}
    	return hp.empty();
    }
    void dfs(int Fa,int t)
    {
    	int i,j,k,l;
    	fa[t]=Fa;
    	if (a[ls[t]][0]==Fa && D[t]==1) {b[t].s1=b[t].s2=0,b[t].id=t;return;}
    	
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	id[a[i][0]]=i,dfs(t,a[i][0]);
    	
    	b[t]=Inf,b[t].id=t;
    	fd(i,n-1,0)
    	{
    		while (!hp.empty()) hp.pop();
    		for (l=ls[t]; l; l=a[l][1])
    		if (a[l][0]!=Fa)
    		hp.push(Add(b[a[l][0]]));
    		
    		b[t]=Xor(b[t],i);
    		if (!pd(b[t]))
    		b[t]=Xor(b[t],i);
    	}
    }
    
    void Dfs(int Fa,int t)
    {
    	int i;
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa && !bz[a[i][0]])
    	{
    		if (a[i][2]>mx) mx=a[i][2],mx2=i;
    		Dfs(t,a[i][0]);
    	}
    }
    
    int Ask(int x,int y) {int s;printf("? %d %d
    ",x,y);fflush(stdout);scanf("%d",&s);return s;}
    void Find(int x) {printf("! %d
    ",x);fflush(stdout);exit(0);}
    
    int main()
    {
    	#ifdef file
    	f1.open("CF1444E.in");
    	#endif
    	
    	p[0]=1;
    	fo(i,1,50) p[i]=p[i-1]*2;
    	#ifdef file
    	f1>>n,len=1;
    	fo(i,1,n-1) f1>>j,f1>>k,New(j,k),New(k,j),++D[j],++D[k];
    	#else
    	scanf("%d",&n),len=1;
    	fo(i,1,n-1) scanf("%d%d",&j,&k),New(j,k),New(k,j),++D[j],++D[k];
    	#endif
    	if (n-1<50) Inf.s2=p[n]-1;
    	else Inf.s1=p[n-50]-1,Inf.s2=p[50]-1;
    	f1.close();
    	
    	dfs(0,1);
    	fo(i,2,n) a[id[i]][2]=a[id[i]^1][2]=f[i];
    	x=1;
    	while (1)
    	{
    		mx=-1,Dfs(0,x);
    		if (mx==-1) Find(x);
    		
    		x=a[mx2][0],y=a[mx2^1][0];
    		z=Ask(x,y),bz[x]=bz[y]=1,bz[z]=0,x=z;
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    typeof的用法
    新建一个express工程,node app无反应
    搜索引擎-倒排索引基础知识
    搭建Hadoop2.6.0+Eclipse开发调试环境(以及log4j.properties的配置)
    hadoop下远程调试方法
    回调函数透彻理解Java
    Maven 手动添加 JAR 包到本地仓库
    Hbase rowkey热点问题
    Hadoop 2.2 & HBase 0.96 Maven 依赖总结
    通过Java Api与HBase交互
  • 原文地址:https://www.cnblogs.com/gmh77/p/13956449.html
Copyright © 2011-2022 走看看