<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Codeforces 1033E. Hidden Bipartite Graph

      題目鏈接:1033E - Hidden Bipartite Graph

      題目大意:交互題,有一個點數為 \(n\le 600\) 的無向連通圖(\(n\) 給定),有 \(20000\) 次詢問機會。每次詢問可以給出一個點集,返回點集內的點兩兩之間一共有多少條邊。要求判斷圖是否為二分圖,若是則輸出其中一邊,若不是則輸出其中一個奇環。

      考慮將圖分層,一開始第一層對應點集 \(S_1={1}\),之后如果對每一層 \(S_i\),都能找到所有與 \(S_i\) 有邊相連的點,那么就能有一個新的點集 \(S_{i+1}\),一直這樣下去就能建起一棵生成樹,實現對圖的分層。

      那么現在就需要處理若干個這樣的子問題:有點集 \(S,T\),要求在 \(T\) 中找到所有與 \(S\) 有邊相連的點。

      考慮分治,對點集 \(T\) ,可以把所有點都存在 vector 中,這樣每個區間就對應著 \(T\) 中的一個子集。我們把 \(T\) 分成兩部分 \(T_L=[l,mid],T_R=(mid,r]\),如果我們能判斷出 \(T_L,T_R\)\(S\) 之間的連邊關系,對有邊的區間繼續詢問下去,就能夠進行遞歸求解求出所有滿足條件的點。

      現在相當于我們需要判斷兩個點集 \(S,t\) 之間是否有連邊,那么我們知道,當詢問的點集為 \(S\cup t\) 時,返回的邊數里包含了 \(S\) 內部以及 \(t\) 內部自身的連邊。所以我們相當于要判斷 \(Ask(S\cup t)-Ask(S)-Ask(t)\) 的值。而由于在每一層,\(S\) 都是固定的,所以可以提前存下 \(Ask(S)\) 的值,就可以做到兩次詢問實現判斷了。

      我們分析一下這樣做需要耗費的詢問次數。其實可以類比線段樹的單點修改操作,對于所有滿足條件的點,與之相關的區間都只會有 \(O(\log n)\) 個,于是可以得出總的詢問次數就是 \(O(n\log n)\) 的。

      現在我們求出了每一層有哪些點,接下去就可以進行判斷。只需要把奇數層和偶數層分別放到一起,判斷內部是否有連邊即可。那么是二分圖的情況非常好弄,直接輸出就好,不是二分圖的情況就不是很好搞,因為我們需要找到一個奇環。

      我們知道,出現矛盾是因為奇數層(或偶數層)內部有邊相連,那么如果我們能夠找到這條邊 \((x,y)\),并找到 \(x\)\(y\) 到這棵生成樹上 \(\operatorname{LCA}(x,y)\) 的路徑,就相當于找到了一個奇環。

      那么這里就面臨著兩個問題:

      • 怎么找到 \((x,y)\)
      • 怎么找到 \(\operatorname{LCA}(x,y)\),或者怎么找一個點 \(x\) 在生成樹上的父親。

      首先,我們可以通過枚舉集合內部的點 \(i\),并判斷 \(i\) 與集合內其他點是否有連邊找到其中的一個端點 \(x\)。找到 \(x\) 之后,我們只需要在剩下的集合中找到一個與 \(x\) 相鄰的點即可。

      而關于找 \(x\) 在生成樹上的父親,我們可以在分層的時候就可以記錄每個點對應的層數 $v_x $,那么我們只需要找到一個在 \(v_x-1\) 層的一個點與 \(x\) 相鄰即可。如果能實現這一操作,我們就能夠一步步往上跳暴力找到兩個點的 \(\operatorname{LCA}\)

      可以發現,這兩個問題最終都需要我們處理一個操作:給定集合 \(T\) 與點 \(x\),找到 \(T\) 中任意一個與 \(x\) 有邊相連的點。可以套用之前的做法分治,但是因為這里只需要找到任意一個滿足條件的點,二分查找就足夠了,這一部分所需要的詢問次數也是 \(O(n\log n)\) 的。

      于是在最壞情況下,每次操作都需要耗費兩個詢問次數,大概需要詢問 \(4n\log n\) 次,正好卡在 \(20000\) 以內,最后本人代碼的最多詢問次數為 \(16675\),還是比較充裕的。

      #include<bits/stdc++.h>
      using namespace std;
      #define N 666
      int n,cnt,v[N],t;
      vector<int>d,s,tmp,O,E,f[N];
      int Ask(vector<int>D)//詢問 
      {
      	if(D.size()<2)return 0;//點集大小不超過2時,可以不用詢問 
      	printf("? %d\n",(int)D.size());
      	for(auto i:D)printf("%d ",i);
      	printf("\n");
      	fflush(stdout);
      	int res;
      	scanf("%d",&res);
      	return res;
      }
      int Count(int l,int r)//計算S和區間[l,r]內的點之間的邊數 
      {
      	tmp.clear();
      	for(int i=l;i<=r;i++)tmp.push_back(d[i]);
      	int Self=Ask(tmp);//計算[l,r]內部邊數 
      	for(auto i:s)tmp.push_back(i);
      	int Sum=Ask(tmp);//計算并集的總邊數 
      	return Sum-Self-t;//t的值在之前已經提前求過了,是S內部的邊數 
      }
      void Find(int l,int r)//利用分治的思想找到每個與S有連邊的點 
      {
      	if(l==r){
      		if(Count(l,r)){//單獨判斷d[l]與S是否有連邊 
      			v[d[l]]=cnt;//v[i]表示i號結點在第幾層 
      			f[cnt].push_back(d[l]);//把每一層的結果存下來,后面找父親要用 
      		}
      		return;
      	}
      	int mid=l+r>>1;//這里的操作和線段樹單點修改類似 
      	if(Count(l,mid))Find(l,mid);
      	if(Count(mid+1,r))Find(mid+1,r);
      }
      int Find2()//已知點x與d內的點有連邊,二分找出一個與x有連邊的點 
      {
      	int l=0,r=d.size()-1;
      	while(l<r){
      		int mid=l+r>>1;
      		if(Count(l,mid))r=mid;
      		else l=mid+1;
      	}
      	return d[l];
      }
      int getf(int x)//對于點x,在樹上的父親一定在v[x]-1這一層 
      {
      	t=0;
      	d=f[v[x]-1];
      	s.clear();
      	s.push_back(x);
      	return Find2();
      }
      void rua(vector<int>D)//找奇環 
      {
      	int m=D.size(),x,y;
      	for(int i=0;i<m;i++){//通過枚舉找到一個與其他點有連邊的x 
      		tmp.clear();
      		for(int j=0;j<m;j++)
      			if(j!=i)tmp.push_back(D[j]);
      		if(Ask(tmp)<t){
      			x=D[i];
      			break;
      		}
      	}
      	t=0;
      	d=tmp;
      	s.clear();
      	s.push_back(x);
      	y=Find2();//找到一個與x有連邊的y 
      	vector<int>ansx,ansy;//分別存儲x,y到其祖先的路徑,直接暴力找LCA 
      	ansx.push_back(x);
      	ansy.push_back(y);
      	while(v[x]<v[y]){
      		x=getf(x);
      		ansx.push_back(x);
      	}
      	while(v[y]<v[x]){
      		y=getf(y);
      		ansy.push_back(y);
      	}
      	while(x!=y){
      		x=getf(x);
      		y=getf(y);
      		ansx.push_back(x);
      		ansy.push_back(y);
      	}
      	printf("N %d\n",ansx.size()+ansy.size()-1);
      	for(auto i:ansx)printf("%d ",i);
      	ansy.pop_back();
      	reverse(ansy.begin(),ansy.end());//因為之前輸出的是x到LCA的路徑,所以要翻轉 
      	for(auto i:ansy)printf("%d ",i);
      }
      int main()
      {
      	scanf("%d",&n);
      	v[1]=++cnt;
      	s.push_back(1);
      	f[1].push_back(1);
      	for(int i=2;i<=n;i++)d.push_back(i);
      	while(!d.empty()){
      		cnt++;
      		t=Ask(s);//提前計算S內部的連邊,減少詢問次數 
      		Find(0,d.size()-1);
      		d.clear(),s.clear();
      		for(int i=1;i<=n;i++){
      			if(!v[i])d.push_back(i); //所有還沒訪問過的點作為集合T
      			if(v[i]==cnt)s.push_back(i);//把當前層的點作為新的S 
      		}
      	}
      	for(int i=1;i<=n;i++)//奇偶分別存,判斷是否存在奇環 
      		if(v[i]&1)O.push_back(i);
      		else E.push_back(i);
      	t=Ask(O);
      	if(t){
      		rua(O);
      		return 0;
      	}
      	t=Ask(E);
      	if(t){
      		rua(E);
      		return 0;
      	}
      	printf("Y %d\n",(int)O.size());
      	for(auto i:O)printf("%d ",i);
      	return 0;
      }
      
      posted @ 2022-07-23 21:01  DeaphetS  閱讀(74)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产毛片基地| 99在线小视频| 无码国内精品久久人妻蜜桃| 日韩av一区二区精品不卡| 国产高清一区二区不卡| 国产jizzjizz视频| 无套内射极品少妇chinese| 久久亚洲精品成人av秋霞| 精品国产一区二区三区av性色| 国产精品国三级国产av| 久久99久国产精品66| 伊人久久大香线蕉综合影院| 一本色道国产在线观看二区| 成年女人免费视频播放体验区| 精品偷自拍另类精品在线| 国产一区二区日韩经典| 精精国产XXX在线观看| 九九热在线精品视频观看| 国产免费久久精品44| 国产乱码精品一区二三区| 中国女人熟毛茸茸A毛片| 免费 黄 色 人成 视频 在 线| 欧美亚洲另类自拍偷在线拍| 亚洲经典在线中文字幕| 国产综合视频一区二区三区| 亚洲一区av无码少妇电影| 亚洲另类激情专区小说图片| 99精品热在线在线观看视| 国产中文字幕精品在线| 久久午夜夜伦鲁鲁片免费无码影院| 欧美色综合天天久久综合精品| 亚洲精品一区二区三区蜜臀| 国产中文字幕精品在线| 国产最新进精品视频| 无套内谢少妇高清毛片| 人妻久久久一区二区三区| 自拍偷区亚洲综合第二区| 成人年无码av片在线观看| 亚洲高清WWW色好看美女| 欧美粗大| 国产精自产拍久久久久久蜜|