JZOJ 3815. 【NOIP2014模拟9.7】克卜勒

Description

一闪一闪亮晶晶/好像你的身体/藏在众多孤星之中/还是找得到你/挂在天上放光明/反射我的孤寂/提醒我/我也只是一颗寂寞的星星/oh~/浩瀚的世界里/更迭的人海里/和你互相辉映/而我们连续/连接所有思念/唱一首歌给你/给你

Zyh在浩瀚的宇宙中发现了一个神奇的星系。这个星系上很可能有文明的痕迹,因为它的星球的连接方式非常特别。
具体的来说整个星系由若干个小星系组成,这若干个小星系是由若干个星球组成的。星系由n个小星系组成,这n个小星系在这里可以抽象成一个小圆。小星系编号1~n首尾相接形成一个大圆。若将第i个小星系放大,那么看到的就是Ci个星球。这些星球也是首尾相接形成了一个大圆。特别地,每个小星系中有两个星球x,y,分别成为起始星球和结束星球。在整个星系大圆的构成中实际上是由上一个小星系的结束星球连接着下一个小星系的起始星球。如果嫌弃语文拿B的Zyh说的不清楚可以看下面的图。

Description

其中用黄绿色细线画的圈是一个个小星系,其中是有若干个星球,红色是起始星球,蓝色是结束星球。
然而星球之间的通信是一个问题。Zyh认为,星球会有两个状态,允许通行和禁止通行。星球的编号即使是在不同的小星系中也是两两不同的,如果是第I个小星系的第J个星球,那么编号应该是[sigma(1<=i

Input

首先是一个正整数n表示小星系的个数,然后是n行。每行的开始是Ci表示这个小星系的星球个数。接着是Ci+2个数字,分别是S[1] …… S[Ci] x y。S[j]表示第i个小星系的第j个星球的通行状态。0表示禁止通行,1表示允许通行。x和y表示这个小星系的第x第y个分别是起始和结束星球。
然后是一个正整数m,表示操作和询问总数。接下来是m行。如果是操作那么是这样的形式给出:1 x,表示将编号为x的星球状态置反。如果是询问:2 x y,表示询问星球x和y能不能互相到达。如果可以输出Yes,否则输出No。

Output

对于每个询问输出对应的答案。

Sample Input

4
3 1 1 0 2 1
2 1 0 2 1
3 0 1 0 1 3
4 0 0 1 1 2 4
12
2 1 2
2 1 4
1 5
2 1 11
1 6
1 7
1 8
2 2 8
1 6
2 2 8
1 10
2 2 8

Sample Output

Yes
No
Yes
Yes
No
Yes

Data Constraint

对于30%的数据 sigma Ci<=1000 , n<=100 , m<=10000
另有10%的数据 Ci<=500000,n=1 , m<=500000
对于100%的数据 sigmaCi<=500000 , n<=10000 , m<=500000 , Ci>1 , x!=y无论是询问还是起始结束星球

Solution

  • 只要用树状数组在小环内维护各个点之间的连通性。(有一个点不连通则整体不连通)

  • 然后将起始点和结束点之间的连通性看成一个点,然后再用另一个树状数组维护即可。

  • 时间复杂度 O(N log N)

  • 要注意很多细节,如 n=1 时起始点和结束点有连边、

  • 当要查询的两点在同一连通块时,可以在块内走,也能在外面绕一大圈走……

Code

#include<cstdio>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=1e4+5,M=5e5+5;
int n,tot,num;
int f[M],g[N];
int a[M],bel[M],l[N],r[N],st[N],ed[N];
bool bz[N];
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
inline void changef(int x,int val)
{
    while(x<=num) f[x]+=val,x+=x&-x;
}
inline void changeg(int x,int val)
{
    while(x<=n) g[x]+=val,x+=x&-x;
}
inline int getf(int x,int y)
{
    int sum=0;
    while(y) sum+=f[y],y-=y&-y;
    for(x--;x;x-=x&-x) sum-=f[x];
    return sum;
}
inline int getg(int x,int y)
{
    int sum=0;
    while(y) sum+=g[y],y-=y&-y;
    for(x--;x;x-=x&-x) sum-=g[x];
    return sum;
}
inline bool check(int x,int y)
{
    if(x>y) swap(x,y);
    return !getf(x,y) || !(getf(l[bel[x]],x)+getf(y,r[bel[x]]));
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        int c=read();
        l[i]=num+1,r[i]=num+c;
        for(int j=num+1;j<=num+c;j++)
        {
            a[j]=read()^1;
            bel[j]=i;
        }
        st[i]=num+read(),ed[i]=num+read();
        num+=c;
    }
    for(int i=1;i<=num;i++)
        if(a[i]) changef(i,1);
    for(int i=1;i<=n;i++)
    {
        int x=st[i],y=ed[i];
        if(x>y) swap(x,y);
        if(getf(x,y) && getf(l[i],x)+getf(y,r[i])) changeg(i,bz[i]=1);
    }
    int m=read();
    while(m--)
    {
        if(read()==1)
        {
            int pos=read();
            changef(pos,(a[pos]^1)-a[pos]);
            a[pos]^=1;
            int z=bel[pos],x=st[z],y=ed[z];
            if(x>y) swap(x,y);
            if(getf(x,y) && getf(l[z],x)+getf(y,r[z]))
            {
                if(!bz[z]) bz[z]=true,changeg(z,1);
            }else
                if(bz[z]) bz[z]=false,changeg(z,-1);
        }else
        {
            int x=read(),y=read();
            if(n==1)
                if(check(x,y) || check(st[1],x) && check(y,ed[1]) || check(ed[1],x) && check(y,st[1]))
                {
                    puts("Yes");
                    continue;
                }
            if(bel[x]==bel[y])
            {
                int z=bel[x];
                if(check(x,y) || !(getg(1,z-1)+getg(z+1,n)) &&
                    (check(st[z],x) && check(y,ed[z]) || check(ed[z],x) && check(y,st[z])))
                    {
                        puts("Yes");
                        continue;
                    }else
                    {
                        puts("No");
                        continue;
                    }
            }
            int xx=bel[x],yy=bel[y];
            if(xx>yy) swap(xx,yy),swap(x,y);
            if(!getg(xx+1,yy-1) && check(x,ed[xx]) && check(st[yy],y))
            {
                puts("Yes");
                continue;
            }
            if(!(getg(1,xx-1)+getg(yy+1,n)) && check(st[xx],x) && check(ed[yy],y))
            {
                puts("Yes");
                continue;
            }
            puts("No");
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值