xtq的口令-赛后题解

· · 题解

如果A同学观察B同学,那么我们连一条从点A到点B的有向边。

在下面的陈述中,我们将“A同学收到指令”称为“点A被染色”。

那么我们就可以把题意转化为:

给定一个有向图,已知当一个点连向的点被染色时,那么这个点也被染色。支持两种操作:

查询操作:给定区间[L,R]内的所有点被染色,那么求还需要给多少点染色,才能使最终所有点被染色。

修改操作:给定区间[L,R]x,将编号在区间[L,R]内的所有点连向x。

下面考虑做法。

参考代码1:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn=300005;

int d[maxn]; //d代表:当前节点出度是否为零。1:出度为零,0:出度非零

int main()
{
    int n,q;
    scanf("%d %d",&n,&q);
    for(int i=1;i<=n;i++) d[i]=1;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d",&x);
        for(int j=1;j<=x;j++)
        {
            scanf("%d",&y);
            d[y]=0; //出度非零
        }
    }
    for(int i=1;i<=q;i++)
    {
        int opt,x,y,z;
        scanf("%d",&opt);
        if(opt==1)
        {
            int sum=0;
            scanf("%d %d",&x,&y);
            for(int j=1;j<x;j++) 
                sum+=d[j];
            for(int j=y+1;j<=n;j++)
                sum+=d[j];
            printf("%d\n",sum);
        }
        if(opt==2)
        {
            scanf("%d %d %d",&x,&y,&z);
            for(int i=x;i<=y;i++) d[i]=0;
        }
    }
    return 0;
}

参考代码2:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn=300005;

int d[maxn],s[maxn]; //s:前缀和

int main()
{
    int n,q;
    scanf("%d %d",&n,&q);
    for(int i=1;i<=n;i++) d[i]=1;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d",&x);
        for(int j=1;j<=x;j++)
        {
            scanf("%d",&y);
            d[y]=0;
        }
    }
    for(int i=1;i<=n;i++) s[i]=s[i-1]+d[i];
    for(int i=1;i<=q;i++)
    {
        int opt,x,y,z;
        scanf("%d",&opt);
        if(opt==1)
        {
            int sum=0;
            scanf("%d %d",&x,&y);
            sum=s[x-1]+s[n]-s[y];
            printf("%d\n",sum);
        }
        if(opt==2)
        {
            scanf("%d %d %d",&x,&y,&z);
            for(int i=x;i<=y;i++) d[i]=0; 
            for(int i=1;i<=n;i++) s[i]=s[i-1]+d[i]; //修改操作后,重新计算前缀和
        }
    }
    return 0;
}

参考代码3:

#include <iostream>
#include <cstdio>
using namespace std;

const int maxn=900005;

struct Node //线段树节点
{
    int left, right;
    int sum, lazy;
}a[maxn];

int ab[maxn],x,y,z,opt,d[maxn];
int n,q;

void buildtree(int id, int l, int r)
{
    a[id].left=l; a[id].right=r; a[id].lazy=0;
    if(l==r)
    {
        if(d[l]==1)
            a[id].sum=0;
        else
            a[id].sum=1;
        return;
    }
    int mid=(l+r)/2;
    buildtree(id<<1,l,mid);
    buildtree(id<<1|1,mid+1,r);
    a[id].sum=a[id<<1].sum+a[id<<1|1].sum;
}

void pushdown(int id)
{
    if(a[id].lazy==1)
    {
        a[id].sum=0;
        a[id<<1].lazy=1;
        a[id<<1|1].lazy=1;
        a[id].lazy=0;
    }
}

int query(int id, int l, int r)
{
    if(a[id].left==l && a[id].right==r)
    {
        if(a[id].lazy==0)
            return a[id].sum;
        else
            return 0;
    }
    pushdown(id);
    if(r<=a[id<<1].right) return query(id<<1,l,r);
    else if(l>=a[id<<1|1].left) return query(id<<1|1,l,r);
    else
    {
        return query(id<<1,l,a[id<<1].right)+query(id<<1|1,a[id<<1|1].left,r);
    }
}

void change(int id, int l, int r)
{
    if(a[id].left==l && a[id].right==r)
    {
        a[id].lazy=1;
        return;
    }
    pushdown(id);
    if(r<=a[id<<1].right) change(id<<1,l,r);
    else if(l>=a[id<<1|1].left) change(id<<1|1,l,r);
    else
    {
        change(id<<1,l,a[id<<1].right);
        change(id<<1|1,a[id<<1|1].left,r);
    }
    a[id].sum=(a[id<<1].lazy==0?a[id<<1].sum:0)+(a[id<<1|1].lazy==0?a[id<<1|1].sum:0);
}

int main()
{
    scanf("%d %d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&ab[i]);
        for(int j=1;j<=ab[i];j++)
        {
            scanf("%d",&x);
            d[x]=1;
        }
    }
    buildtree(1,1,n);
    for(int i=1;i<=q;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d %d",&x,&y);
            printf("%d\n",query(1,1,n)-query(1,x,y));
        }
        else
        {
            scanf("%d %d %d",&x,&y,&z);
            change(1,x,y);
        }
    }
    return 0;
}