zoukankan      html  css  js  c++  java
  • 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 }

    就算孤岛已没有四季  也没人提及你的美丽  我还是要飞去那里
  • 相关阅读:
    C#读取资源文件的两种方法及保存资源文件到本地
    T4模板编辑器
    VS (Visual Studio) 快捷键
    以太网帧类型速查
    线程间操作无效: 从不是创建控件“XXX”的线程访问它
    C# 集合
    C#控件之ListView
    C# Color颜色对照表
    Java的内存需要划分成为5个部分:
    Java学习:数组的使用和注意事项
  • 原文地址:https://www.cnblogs.com/ZYBGMZL/p/6868822.html
Copyright © 2011-2022 走看看