luogu P3398 仓鼠找sugar [LCA]
题目描述
小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?
小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧!
输入输出格式
输入格式:
第一行两个正整数n和q,表示这棵树节点的个数和询问的个数。
接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。
接下来q行,每行四个正整数a、b、c和d,表示节点编号,也就是一次询问,其意义如上。
输出格式:
对于每个询问,如果有公共点,输出大写字母“Y”;否则输出“N”。
输入输出样例
输入样例#1:
5 5 2 5 4 2 1 3 1 4 5 1 5 1 2 2 1 4 4 1 3 4 3 1 1 5 3 5 1 4
输出样例#1:
Y N Y Y Y
说明
本题时限1s,内存限制128M,因新评测机速度较为接近NOIP评测机速度,请注意常数问题带来的影响。
20%的数据 n<=200,q<=200
40%的数据 n<=2000,q<=2000
70%的数据 n<=50000,q<=50000
100%的数据 n<=100000,q<=100000
My Solution
借用题解里沧澜的原话:
如果两条路径相交,那么一定有一条路径的LCA在另一条路径上
而判断一个节点x,是否在路径s-t上需要满足如下几个条件
- deep[x]>=deep[LCA(s,t)]
- LCA(s,x)=x或LCA(t,x)=x;
所以分两种情况讨论一下即可
剩下的就是lca模板了,找根我用了点分治里找重心
暂时只会倍增lca QwQ
再犯sb错误,把&打成了&&
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<vector> 5 using namespace std; 6 #define q1 first 7 #define q2 second 8 #define ss first 9 #define tt second 10 11 inline int read(){ 12 char ch; 13 int re=0; 14 bool flag=0; 15 while((ch=getchar())!='-'&&(ch<'0'||ch>'9')); 16 ch=='-'?flag=1:re=ch-'0'; 17 while((ch=getchar())>='0'&&ch<='9') re=re*10+ch-'0'; 18 return flag?-re:re; 19 } 20 21 struct edge{ 22 int to,next; 23 edge(int to=0,int next=0): 24 to(to),next(next){}; 25 }; 26 const int maxn=100001; 27 const int maxm=maxn<<1; 28 const int maxlogn=17; 29 typedef pair<int,int> PII; 30 typedef pair<PII,PII> PP; 31 int n,q; 32 vector<PP> ques; 33 int cnt=0; 34 int head[maxn]; 35 edge edges[maxm]; 36 int root; 37 int F[maxn],son[maxn]; 38 bool vis[maxn]; 39 int depth[maxn],parent[maxlogn][maxn]; 40 int sum; 41 42 inline void add_edge(int from,int to){ 43 edges[++cnt]=edge(to,head[from]); 44 head[from]=cnt; 45 edges[++cnt]=edge(from,head[to]); 46 head[to]=cnt; 47 } 48 49 inline void add_ques(int a,int b,int c,int d){ 50 ques.push_back(make_pair(make_pair(a,b),make_pair(c,d))); 51 } 52 53 void getroot(int x,int fa){ 54 son[x]=1; F[x]=0; 55 for(int ee=head[x];ee;ee=edges[ee].next) 56 if(edges[ee].to!=fa&&!vis[edges[ee].to]){ 57 getroot(edges[ee].to,x); 58 son[x]+=son[edges[ee].to]; 59 F[x]=max(F[x],son[edges[ee].to]); 60 } 61 F[x]=max(F[x],sum-son[x]); 62 if(F[x]<F[root]) root=x; 63 } 64 65 void dfs(int v,int fa,int deep){ 66 parent[0][v]=fa; 67 depth[v]=deep; 68 for(int ee=head[v];ee;ee=edges[ee].next) 69 if(edges[ee].to!=fa) dfs(edges[ee].to,v,deep+1); 70 } 71 72 void init(){ 73 memset(head,0,sizeof head); 74 n=read(),q=read(); 75 for(int i=0;i<n-1;i++){ 76 int from=read(),to=read(); 77 add_edge(from,to); 78 } 79 for(int i=0;i<q;i++){ 80 int a=read(),b=read(),c=read(),d=read(); 81 add_ques(a,b,c,d); 82 } 83 memset(vis,0,sizeof vis); 84 sum=F[root=0]=n; 85 getroot(1,0); 86 dfs(root,-1,0); 87 for(int k=0;k+1<maxlogn;k++) 88 for(int v=1;v<=n;v++) 89 if(parent[k][v]<0) parent[k+1][v]=-1; 90 else parent[k+1][v]=parent[k][parent[k][v]]; 91 } 92 93 int lca(int u,int v){ 94 if(depth[u]>depth[v]) swap(u,v); 95 for(int k=0;k<maxlogn;k++) 96 if(depth[v]-depth[u]>>k&1) 97 v=parent[k][v]; 98 if(u==v) return u; 99 for(int k=maxlogn-1;k>=0;k--) 100 if(parent[k][u]!=parent[k][v]){ 101 u=parent[k][u]; 102 v=parent[k][v]; 103 } 104 return parent[0][u]; 105 } 106 107 bool check(PP qu){ 108 int lca1=lca(qu.q1.ss,qu.q1.tt),lca2=lca(qu.q2.ss,qu.q2.tt); 109 if(depth[lca1]>=depth[lca2]&&(lca1==lca(qu.q2.ss,lca1)||lca1==lca(qu.q2.tt,lca1))) 110 return 1; 111 if(depth[lca2]>=depth[lca1]&&(lca2==lca(qu.q1.ss,lca2)||lca2==lca(qu.q1.tt,lca2))) 112 return 1; 113 return 0; 114 } 115 116 void solve(){ 117 for(int i=0;i<q;i++) 118 if(check(ques[i])) puts("Y"); 119 else puts("N"); 120 } 121 122 int main(){ 123 //freopen("temp.in","r",stdin); 124 init(); 125 solve(); 126 return 0; 127 }
就算孤岛已没有四季 也没人提及你的美丽 我还是要飞去那里