JZOJ-senior-3910. 【NOIP2014模拟11.1A组】Idiot 的间谍网络

3910. 【NOIP2014模拟11.1A组】Idiot 的间谍网络 (Standard IO)

Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits

Description

作为一名高级特工,Idiot 苦心经营多年,终于在敌国建立起一张共有n 名特工的庞大间谍网络。
当然,出于保密性的要求,间谍网络中的每名特工最多只会有一名直接领导。现在,Idiot 希望整理有关历次特别行动的一些信息。
初始时,间谍网络中的所有特工都没有直接领导。之后,共有m 次下列类型的事件按时间顺序依次发生:
• 事件类型1 x y:特工y 成为特工x 的直接领导。数据保证在此之前特工x 没有直接领导;
• 事件类型2 x:特工x 策划了一起特别行动,然后上报其直接领导审批,之后其直接领导再上报其直接领导的直接领导审批,以此类推,直到某个特工审批后不再有直接领导;
• 事件类型3 x y:询问特工x 是否直接策划或审批过第y 次特别行动。所有特别行动按发生时间的顺序从1 开始依次编号。数据保证在询问之前,第y 次特别行动已经发生过。
作为一名高级特工,Idiot 当然不会亲自办事。于是,Idiot 便安排你来完成这个任务。

Input

第一行两个正整数n 和m,分别表示间谍网络中的特工总数,以及事件的总数。
接下来m 行,第i 行给出第i 个事件的信息,格式及含义参见题面。

Output

输出共t 行,其中t 表示询问的总数。第i 行输出”Y ES” 或者”NO”,表示第i 次询问的答案。

Sample Input

6 12
2 1
1 4 1
3 4 1
1 3 4
2 3
3 4 1
2 3
3 4 2
3 1 1
3 1 3
3 1 2
1 2 4

Sample Output

NO
NO
YES
YES
YES
YES

扫描二维码关注公众号,回复: 1826916 查看本文章

Data Constraint

对于30% 的数据,n <= 3 10^3,m <= 5 10^3;
对于60% 的数据,n <=2 * 10^5,m <= 2 * 10^5;
额外20% 的数据,保证在任意时刻,整张间谍网络由若干条互不相交的链构成;
对于100% 的数据,n <= 5 * 10^5,m <= 5 * 10^5;
C + + 选手的程序在评测时使用编译选项-Wl;–stack = 104857600。

Solution

算法一
对于操作二,每次暴力将其到树根的路径上所有点增加一个新标记,然后对操作三直接查询。
时间复杂度 Θ(nm)。期望得分 30 分。

算法二
对于询问,可以发现其等价于查询:给定点是否为当次操作的操作点的祖先;在当前的关系图中,给定点和当次操作的操作点是否连通。因此,可以将所有询问全部挂在对应的操作二处,然后在处理每个操作二时,直接回答所有与其相关的询问。对于若干条链的情形,考虑采取离线的方式,首先按照最后的关系图计算出每个点的深度,然后在处理事件的过程中用并查集来维护连通性。
时间复杂度 Θ(α(n)n)。结合算法一,期望得分 50 分。

算法三
在更一般的情形中,仍然可以沿用算法二的方法。对于连通性,依然采用并查集的方式;对于是否为其祖先的查询,可以通过倍增转化为查询lca(x, y) = x 是否成立,其中 x 为给定点,y 为当次操作的操作点。
时间复杂度 Θ(n log(n))。结合算法二,期望得分 80 分。

算法四
在算法三中,对于一个点是否为另一个点祖先的询问,其实可以直接使用 dfs 序来解决。若记 Li为进入子树 i 时的时间戳,Ri 为离开子树 i 时的时间戳,则 x 为 y 的祖先等价于 Lx ≤ Ly 并且Ry ≤ Rx。因此,只需在预处理时对森林中的每棵树进行一遍 dfs 即可。
时间复杂度 Θ(α(n)n)。期望得分 100 分。

Code

#include<algorithm>
#include<cstring>
#include<cstdio>
#define N 500010
using namespace std;
int t,i,j,n,m,x,y,c,k,bb,dd;
int f[N],g[N],last[N],num[N][3];//f:父节点编号;g:遍历顺序;num:时间戳;
int a[N][3],d[N][3],e[N][3];//d[i]:策划行动的时间及人物;e[i]:人物关系;
bool bz[N];
struct node {int x,y,z,s;}b[N];//询问;
int get(int v) {if (f[v]!=v) f[v]=get(f[v]); return f[v];}
void merge(int u,int v) {int fu=get(u),fv=get(v); f[fu]=fv;}
void link(int x,int y) {a[++t][1]=y,a[t][2]=last[x],last[x]=t;}
bool cmp(node p,node q) {return p.y<q.y;}
bool cmd(node p,node q) {return p.z<q.z;}
void dfs(int x,int fa)
{
    k++,bz[x]=true,num[x][1]=k,g[x]=k;
    for(int w=last[x]; w; w=a[w][2]) if (a[w][1]!=fa)
    {
        dfs(a[w][1],x);
        num[x][2]=k;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(i=1; i<=n; i++) f[i]=i;
    for(i=1; i<=m; i++)
    {
        scanf("%d",&c);
        if (c==2) scanf("%d",&d[++dd][1]),d[dd][2]=i;
        else 
        {
            scanf("%d%d",&x,&y);
            if (c==1) link(y,x),merge(x,y),e[i][1]=x,e[i][2]=y;
            else b[++bb].x=x,b[bb].y=y,b[bb].z=i;
        }
    }
    memset(bz,0,sizeof(bz));
    for(i=1; i<=n; i++) {int p=get(i); if (!bz[p]) dfs(p,0);}
    for(i=1; i<=n; i++) if (num[i][2]==0) num[i][2]=num[i][1];
    sort(b+1,b+1+bb,cmp);
    for(i=1; i<=n; i++) f[i]=i;
    int l=1,r=1;
    for(i=1; i<=dd; i++)
    {
        for(j=l; j<=d[i][2]; j++) if (e[j][1]) merge(e[j][1],e[j][2]);
        l=d[i][2]+1;
        while (b[r].y==i)
        {
            int u=get(d[i][1]),v=get(b[r].x);
            if (u==v && num[b[r].x][1]<=g[d[i][1]] && g[d[i][1]]<=num[b[r].x][2]) b[r].s=1; else b[r].s=-1;
            r++;
        }
    }
    sort(b+1,b+1+bb,cmd);   
    for(i=1; i<=bb; i++) if (b[i].s==1) printf("YES\n"); else printf("NO\n");
}

猜你喜欢

转载自blog.csdn.net/huangxinyue1017/article/details/79197054
今日推荐