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;
}