P3398 仓鼠找sugar(树链剖分)【洛谷P3398】 仓鼠找sugar

P3398 仓鼠找sugar

问题叙述

题材叙述

多少仓鼠的同外的基(mei)友(zi)sugar住在暗洞穴中,每个节点的数码为1~n。地下洞穴是一个树形结构。这无异于天微微仓鼠打算于自他的起居室(a)到餐厅(b),而异的基友同时使由他的卧房(c)到图书馆(d)。他们还见面走最缺乏路径。现在多少仓鼠希望知道,有无起或以有地方,可以遇到他的基友?

小仓鼠那么死亡,还要随时让zzq大爷虐,请您快来救救他吧!

多少仓鼠的及外的基(mei)友(zi)sugar住在地下隧洞中,每个节点的号子也1~n。地下隧洞是一个树形结构。这等同上微微仓鼠打算于于他的起居室(a)到食堂(b),而异的基友同时使于他的卧房(c)到图书馆(d)。他们还见面移动最差路径。现在有点仓鼠希望知晓,有没发或当有地方,可以遇到他的基友?

输入输出格式

输入格式:

 

先是行两单正整数n和q,表示即株树节点的个数与了解的个数。

紧接下去n-1行,每行两独刚整数u和v,表示节点u到节点v之间出同漫长边。

连通下去q行,每行四单刚整数a、b、c和d,表示节点编号,也就是均等次询问,其意思如齐。

 

输出格式:

 

对此每个询问,如果产生公共点,输出大写字母“Y”;否则输出“N”。

 

稍许仓鼠那么亡,还要天天让zzq大爷虐,请你快来救救他吧!

输入输出样例

输入样例#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

输入输出格式

输入格式:

 

率先实施两独正整数n和q,表示即株树节点的个数与了解的个数。

连片下n-1行,每行两只刚整数u和v,表示节点u到节点v之间出雷同漫漫边。

对接下q行,每行四独刚整数a、b、c和d,表示节点编号,也尽管是一模一样不成询问,其意义如齐。

 

输出格式:

 

对每个询问,如果发公共点,输出大写字母“Y”;否则输出“N”。

 

说明

主题时限1s,内存限制128M,因新评测机速度比较类似NOIP评测机速度,请留心常数问题牵动的熏陶。

20%的数据 n<=200,q<=200

40%的数据 n<=2000,q<=2000

70%的数据 n<=50000,q<=50000

100%的数据 n<=100000,q<=100000

输入输出样例

输入样例#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

分析

设a,b的LCA是x,c,d的LCA是y。如果dep[x]>dep[y],x是比充分的,如果c,d中一个,满足LCA(c/d,x)==x,就发出交点。

寻找LCA,用树链剖分是得的

说明

主题时限1s,内存限制128M,因新评测机速度较接近NOIP评测机速度,请小心常数问题牵动的影响。

20%的数据 n<=200,q<=200

40%的数据 n<=2000,q<=2000

70%的数据 n<=50000,q<=50000

100%的数据 n<=100000,q<=100000

code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 const int MAXN = 100100;
 7 struct Edge{
 8     int to,nxt;
 9 }e[MAXN<<1];
10 int head[MAXN],dep[MAXN],top[MAXN],siz[MAXN],fa[MAXN],son[MAXN];
11 int n,m,q,tot;
12 
13 void add(int u,int v)
14 {
15     ++tot;
16     e[tot].to = v;
17     e[tot].nxt = head[u];
18     head[u] = tot;
19 }
20 void dfs1(int u,int f,int d)    //找重孩子 
21 {
22     dep[u] = d;
23     fa[u] = f;
24     siz[u] = 1;
25     for (int i=head[u]; i; i=e[i].nxt)
26     {
27         int v = e[i].to;
28         if (v!=f)
29         {
30             dfs1(v,u,d+1);
31             siz[u] += siz[v];
32             if (siz[v]>siz[son[u]])//son[]数组,用来保存重儿子
33                 son[u] = v;
34         }
35     }
36 }
37 void dfs2(int x)    //找重链 
38 {
39     int t = 0;
40     if (!top[x]) top[x] = x;
41     for (int i=head[x]; i; i=e[i].nxt)
42         if (fa[x]!=e[i].to&&siz[t]<siz[e[i].to]) 
43             t = e[i].to;
44     if (t) top[t] = top[x], dfs2(t);
45     for (int i=head[x]; i; i=e[i].nxt)
46         if(fa[x]!=e[i].to&&t!=e[i].to) dfs2(e[i].to);
47 }
48 
49 int LCA(int x,int y)
50 {
51     while (top[x]!=top[y])
52     {
53         if (dep[top[x]]<dep[top[y]]) swap(x,y);
54         x = fa[top[x]];
55     }
56     if(dep[x]>dep[y]) swap(x,y);
57     return x;
58 }
59 int main()
60 {
61     scanf("%d%d",&n,&q);
62     for (int x,y,i=1; i<n; ++i)
63     {
64         scanf("%d%d",&x,&y);
65         add(x,y);add(y,x);
66     }
67     dfs1(1,0,1);
68     dfs2(1);
69     while (q--)
70     {
71         int a,b,c,d;
72         scanf("%d%d%d%d",&a,&b,&c,&d);
73         int tmp1 = LCA(a,b), tmp2 = LCA(c,d);
74         if (dep[tmp1]<dep[tmp2]) swap(tmp1,tmp2),swap(a,c),swap(b,d);
75         if (LCA(tmp1,c)==tmp1||LCA(tmp1,d)==tmp1) printf("Y\n");
76         else printf("N\n");
77     }
78     return 0;
79 }

 

题解:

转自:http://www.cnblogs.com/jsawz/p/6817094.html

同志提高+/省选-的问题,终于可以增进博客题目的平均难度了。。。

大概题意就是在平等株树上有一定量条路线,询问这半只途径是无是得结识。

若是而简单长达路子相交的话,一定生平等长路径a两端点之LCA在其他一样久之路线上,我们可通过请路径a的LCA是匪是在路径b上来呼吁出a与b是休是轧的。

冲上述推断,可以包了路径a的LCA的深一定过路径b的LCA的深浅。只要再于确定路径a的LCA与路径b的有数端点内一些底LCA是路径a的LCA就保险路径a的LCA在路径b上了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100000+5;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,q,m,num;
int head[maxn],dep[maxn],f[maxn][18];
bool vis[maxn];
struct node
{
    int next,to;
}e[maxn*2];
void add(int from,int to)
{
    e[++num].next=head[from];
    e[num].to=to;
    head[from]=num;
}
void dfs(int x,int d)
{
    vis[x]=1;dep[x]=d;
    for(int i=head[x];i;i=e[i].next)
    {
        int to=e[i].to;
        if(!vis[to])
        {
            dep[to]=dep[x]+1;
            dfs(to,d+1);
            f[to][0]=x;
        }
    }
}
int Lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=m;i>=0;i--)
        if(dep[x]-(1<<i)>=dep[y])
            x=f[x][i];
    if(x==y) return x;
    for(int i=m;i>=0;i--)
    if(f[x][i]&&f[x][i]!=f[y][i])
    {
        x=f[x][i];
        y=f[y][i];
    }
    return f[x][0];
}
int main()
{
    n=read();q=read();
    m=floor(log((double)n)/log(2.0));
    for(int i=1;i<n;i++)
    {
        int x,y;
        x=read();y=read();
        add(x,y);add(y,x);
    }
    dfs(1,1);
    for(int j=1;j<=m;j++)
    for(int i=1;i<=n;i++)
    f[i][j]=f[f[i][j-1]][j-1];
    for(int i=1;i<=q;i++)
    {
        int a,b,c,d,x,y;
        a=read();b=read();c=read();d=read();
        x=Lca(a,b);y=Lca(c,d);
        if(dep[x]==dep[y]) 
        {
            if(x==y)
            {printf("Y\n");continue;}
            else
            {printf("N\n"); continue;}
        }
        if(dep[x]<dep[y]){
        if(Lca(y,a)==y||Lca(y,b)==y)
            printf("Y\n");
            else
            printf("N\n");
        }
        if(dep[x]>dep[y]){
            if(Lca(x,c)==x||Lca(x,d)==x)
                printf("Y\n");
            else
                printf("N\n");
        }
    }
    return 0;
}

 

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define Me(Arr) memset(Arr,0,sizeof Arr);
using namespace std;
const int maxn=100005,maxe=200005;
int n,Q;
int lnk[maxn],nxt[maxe],son[maxe],tot;
int size[maxn],fa[maxn],dep[maxn],gonxt[maxn],id[maxn],top[maxn],bottom[maxn],cloc;
int bel[maxn],cnt;
bool vis[maxn];
int read(){
    int x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
void INIT(){
    tot=cloc=cnt=0;
    Me(lnk); Me(nxt); Me(son); Me(size);
    Me(fa); Me(dep); Me(gonxt); Me(id); Me(top); Me(bottom); Me(bel);
}
void add(int x,int y){
    nxt[++tot]=lnk[x],son[tot]=y,lnk[x]=tot;
}
void DFS_1(int x,int u,int layer){
    size[x]=1,fa[x]=u,dep[x]=layer;
    for (int j=lnk[x]; j; j=nxt[j]) if (son[j]!=u){
        DFS_1(son[j],x,layer+1); size[x]+=size[son[j]];
        if (size[gonxt[x]]<size[son[j]]) gonxt[x]=son[j];
    }
}
void DFS_2(int x){
    id[x]=++cloc,bottom[x]=x;
    if (gonxt[x]){top[gonxt[x]]=top[x],bel[gonxt[x]]=bel[x]; DFS_2(gonxt[x]); bottom[x]=bottom[gonxt[x]];}
    for (int j=lnk[x]; j; j=nxt[j]) if (son[j]!=fa[x]&&son[j]!=gonxt[x]){
        top[son[j]]=son[j],bel[son[j]]=++cnt;
        DFS_2(son[j]);
    }
}
void prepare(){
    DFS_1(1,0,1); top[1]=bottom[1]=cnt=bel[1]=1; DFS_2(1);
}
int get(int x,int y){
    if (bel[x]==bel[y]) return dep[x]<dep[y]?x:y;
    while (bel[x]!=bel[y]){
        if (dep[top[x]]>dep[top[y]]) x=fa[top[x]]; else y=fa[top[y]];
    }
    return dep[x]<dep[y]?x:y;
}
int main(){
    n=read(),Q=read(),INIT();
    for (int i=1; i<n; i++){
        int x=read(),y=read(); add(x,y),add(y,x);
    }
    prepare();
    for (; Q; Q--){
        int a=read(),b=read(),c=read(),d=read();
        int fx=get(a,b),fy=get(c,d);
        if (dep[fx]<dep[fy]) swap(a,c),swap(b,d),swap(fx,fy);
        if (fx==get(fx,c)||fx==get(fx,d)) puts("Y"); else puts("N");
    }
    return 0;
}

 

相关文章