[URAL2085]Magic Programmer

XIV.[URAL2085]Magic Programmer

如何处理路径上所有东西出现且只出现一次的限制呢?我们考虑哈希。只需要用一个哈希表处理所有出现过的东西,然后求另一半东西时,找出它的补集的哈希值在哈希表中查询,即可做到路径拼接。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int bas1=17680321,bas2=19260817;
struct HASH:pair<ull,ull>{
	void operator ^=(const HASH &x){first^=x.first,second^=x.second;}
}hs[100100],now1,now2;
map<HASH,pair<int,int> >mp;
int n,m,sz[100100],msz[100100],ROOT,SZ,cnt1[100100],cnt2[100100],resu,resv,resw;
vector<int>v[100100],u[100100];
bool vis[100100];
void getroot(int x,int fa){
	msz[x]=0,sz[x]=1;
	for(auto y:v[x])if(y!=fa&&!vis[y])getroot(y,x),sz[x]+=sz[y],msz[x]=max(msz[x],sz[y]);
	msz[x]=max(msz[x],SZ-sz[x]);
	if(msz[x]<msz[ROOT])ROOT=x;
}
void getsz(int x,int fa){
	sz[x]=1;
	for(auto y:v[x])if(y!=fa&&!vis[y])getsz(y,x),sz[x]+=sz[y];
}
void getwrite(int x,int fa,int DEP){
	bool ok=true;
	for(auto i:u[x])if(!cnt1[i]++)now1^=hs[i];else ok=false;
	if(ok){
		mp[now1]=max(mp[now1],make_pair(DEP,x));
		for(auto y:v[x])if(y!=fa&&!vis[y])getwrite(y,x,DEP+1);		
	}
	for(auto i:u[x])if(!--cnt1[i])now1^=hs[i];
}
void getread(int x,int fa,int DEP){
	bool ok=true;
	for(auto i:u[x])if(!cnt2[i]++)now2^=hs[i];else ok=false;
	if(ok){
		if(mp.find(now2)!=mp.end()){
			auto tmp=mp[now2];
			if(tmp.first+DEP>resw)resw=tmp.first+DEP,resu=tmp.second,resv=x;
		}
		for(auto y:v[x])if(y!=fa&&!vis[y])getread(y,x,DEP+1);		
	}
	for(auto i:u[x])if(!--cnt2[i])now2^=hs[i];
}
void getans(int x){
	for(auto i:u[x])if(!cnt1[i]++)now1^=hs[i];
	mp[now1]=max(mp[now1],make_pair(1,x));
	for(auto y:v[x])if(!vis[y])getread(y,x,1),getwrite(y,x,2);
	for(auto i:u[x])if(!--cnt1[i])now1^=hs[i];
	mp.clear();
}
void solve(int x){
	getans(x),getsz(x,0),vis[x]=true;
	for(auto y:v[x])if(!vis[y])ROOT=0,SZ=sz[y],getroot(y,0),solve(ROOT);
}
int main(){
	scanf("%d%d",&n,&m);
	hs[0].first=hs[0].second=1;for(int i=1;i<=m;i++)hs[i].first=hs[i-1].first*bas1,hs[i].second=hs[i-1].second*bas2,now2^=hs[i];
	for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
	for(int i=1,x,y;i<=n;i++){
		scanf("%d",&x);
		if(x==m)resu=resv=i,resw=1;
		while(x--)scanf("%d",&y),u[i].push_back(y);
	}
	SZ=n,msz[0]=n+1,getroot(1,0),solve(ROOT);
	if(!resw)puts("No solution");else printf("%d %d\n",resu,resv);
	return 0;
}

posted @ 2021-04-01 13:09  Troverld  阅读(48)  评论(0编辑  收藏  举报