JZOJ3815. 【NOIP2014模拟9.7】克卜勒

30 篇文章 0 订阅
18 篇文章 0 订阅

Description

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

Zyh在浩瀚的宇宙中发现了一个神奇的星系。这个星系上很可能有文明的痕迹,因为它的星球的连接方式非常特别。
具体的来说整个星系由若干个小星系组成,这若干个小星系是由若干个星球组成的。星系由n个小星系组成,这n个小星系在这里可以抽象成一个小圆。小星系编号1~n首尾相接形成一个大圆。若将第i个小星系放大,那么看到的就是Ci个星球。这些星球也是首尾相接形成了一个大圆。特别地,每个小星系中有两个星球x,y,分别成为起始星球和结束星球。在整个星系大圆的构成中实际上是由上一个小星系的结束星球连接着下一个小星系的起始星球。如果嫌弃语文拿B的Zyh说的不清楚可以看下面的图。
这里写图片描述
其中用黄绿色细线画的圈是一个个小星系,其中是有若干个星球,红色是起始星球,蓝色是结束星球。
然而星球之间的通信是一个问题。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无论是询问还是起始结束星球

题解

先考虑单个环的情况,不考虑大的那个特殊环。
只要判断x到y的路径上面是否全部是1即可。
在单独一个环里面,从x到y(x < y)的路径有两种,
1、x->y
2、y->n->1->x
只有这两种情况。

再考虑在大的特殊环的情况
假设查询第xx环中的第x号点和第yy环中个第y号点,
参照上面,情况同样只有两种
1、x-> stxx ,y-> fiyy ,大环xx-1 -> yy+1
2、x-> fixx ,y-> styy ,大环xx+1 -> yy-1
如果两个点同在一个小环里面,就还有特殊判断一下。

对于修改操作,就先对小环的进行修改,
然后判断修改过后小环的通过性是否被改变,决定是否需要修改大环上面的信息。

维护区间和可以用线段树,或者用树状数组(推荐使用,更好打)。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 500003
#define M 10003
#define db double
#define P putchar
#define G getchar
#define inf 998244353
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int t[3][4*N],st[N],fi[N];
int n,m,Q,cz,x,y,s[M],xx,yy;
bool it[N+M],ans,old,ne,all[N];

int x_(int x){return x&(-x);}

void ins(int x,int y,int z)
{
    int m=(y==1?s[n]:n);
    for(int i=x;i<=m;i+=x_(i))
        t[y][i]+=z;
}

int get(int x,int y)
{
    int s=0;
    for(int i=x;i;i-=x_(i))
        s+=t[y][i];
    return s;
}

int find(int x,int l,int r)
{
    return get(r,x)-get(l-1,x);
}

bool que(int cnt,int x,int y)
{
    if(x>y)swap(x,y);
    if(find(1,x,y)==y-x+1)return 1;
    if(find(1,s[cnt-1]+1,x)==x-s[cnt-1] && find(1,y,s[cnt])==s[cnt]-y+1)return 1;
    return 0;
}

bool que_(int x,int y)
{
    if(x>y)swap(x,y);
    if(find(2,x,y)==y-x+1)return 1;
    if(find(2,1,x)==x && find(2,y,n)==n-y+1)return 1;
    return 0;
}

int main()
{
    read(n);
    for(int i=1;i<=n;i++)
    {
        read(m);s[i]=s[i-1];
        for(int j=1;j<=m;j++)
            read(x),it[++s[i]]=x;
        read(st[i]);read(fi[i]);
    }

    for(int i=1;i<=s[n];i++)
        if(it[i])ins(i,1,1);

    for(int i=1;i<=n;i++)
        if(que(i,st[i]+s[i-1],fi[i]+s[i-1]))ins(i,2,1),all[i]=1;

    read(Q);
    while(Q--)
    {
        read(cz);
        if(cz==1)
        {
            read(x);
            xx=lower_bound(s+1,s+1+n,x)-s;
            old=que(xx,st[xx]+s[xx-1],fi[xx]+s[xx-1]);

            ins(x,1,it[x]?-1:1);
            it[x]=1-it[x];

            ne=que(xx,st[xx]+s[xx-1],fi[xx]+s[xx-1]);
            if(old!=ne)
            {
                ins(xx,2,all[xx]?-1:1);
                all[xx]=1-all[xx];
            }
        }
        else
        {
            read(x);read(y);
            if(x>y)swap(x,y);
            xx=lower_bound(s+1,s+1+n,x)-s;
            yy=lower_bound(s+1,s+1+n,y)-s;

            ans=que(xx,st[xx]+s[xx-1],x) &&
                que(yy,fi[yy]+s[yy-1],y) &&
                ((xx!=1?xx-1:n)==yy || que_(xx!=1?xx-1:n,yy!=n?yy+1:1));

            ans|=que(xx,x,fi[xx]+s[xx-1]) &&
                que(yy,y,st[yy]+s[yy-1]) &&
                ((xx!=n?xx+1:1)==yy || que_(xx!=n?xx+1:1,yy!=1?yy-1:n));
            if(xx==yy)
                ans|=que(xx,x,y);

            if(ans)P('Y'),P('e'),P('s');
                else P('N'),P('o');
            P('\n');
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值