题解 P5836 【[USACO19DEC]Milk Visits(silver)】

· · 题解

即是只用了10min不到,由大常数选手编写,O(n)还是毫无悬念拿了最优解。

大家都把问题想复杂了,这题根本用不到lca。

为什么这道题特意只给了两种颜色?

因为只有两种颜色时,想要输出0,必须是一条路径上全都是另一种颜色。因此我们把题目转化为了如何判断一条路径是否同色。

我们用top[i]表示i号点向上连续与它同色最多能走到哪里。即

top[i]= top[father[i]],if(color[father[i]]==color[i]) i,if(color[father[i]]!=color[i])

那么路径i->j同色当且仅当top[i]==top[j]

``` #include<cstdio> typedef long long ll; typedef long double ld; const int N=1e5+10; void file(const char *str){ char in[100],out[100]; sprintf(in,"%s.in",str),sprintf(out,"%s.out",str); freopen(in,"r",stdin),freopen(out,"w",stdout); } #define fast_io #ifdef fast_io const int _IB=1e6; char _ibuf[_IB],*_s,*_t; #define getchar()\ (_s==_t&&(_t=(_s=_ibuf)+fread(_ibuf,1,_IB,stdin),_s==_t)?EOF:*_s++) #endif ll read(){ ll a=0;int op=1;char ch=getchar(); while(ch<'0'||'9'<ch){if(ch=='-')op=-1;ch=getchar();} while('0'<=ch&&ch<='9'){a=(a<<3)+(a<<1)+(48^ch);ch=getchar();} return a*op; } int read_color(){ char c; while((c=getchar())!=EOF){ switch(c){ case 'H':return 0; case 'G':return 1; } } return -1; } struct L{ int to,next; }; int head[N]; L l[N<<1]; int lcount; void add(int from,int to){ l[++lcount].to=to; l[lcount].next=head[from]; head[from]=lcount; } #define REPL(S,I,T) for(int I=head[S],T;T=l[I].to,I;I=l[I].next) int n,m; int c[N]; int top[N]; void dfs(int now=1,int t=1,int f=0){ top[now]=t; REPL(now,i,to)if(f!=to)dfs(to,c[to]==c[now]?t:to,now); } void input(){ n=read(); m=read(); for(int i=1;i<=n;i++)c[i]=read_color(); int p1,p2; for(int i=1;i<n;i++){ p1=read(); p2=read(); add(p1,p2); add(p2,p1); } } void ini(){ dfs(); } void solve(){ int p1,p2,p3; for(int i=0;i<m;i++){ p1=read(); p2=read(); p3=read_color(); printf("%d",c[p1]==p3||c[p2]==p3||top[p1]!=top[p2]?1:0); } } void output(){ } void test(){ input(); ini(); solve(); output(); } void all(){ file("tmp"); test(); } int main(){ all(); return 0; } ```