[NOIP2018模拟赛10.22]咕咕报告

闲扯

这是篇咕咕了的博客

考场上码完暴力后不知道干什么,然后忽然发现这个T1好像有点像一道雅礼集训时讲过的CF题目 Rest In Shades ,当时那道题还想了挺久不过思路比较妙,于是我就也\(yy\)出了一个二分+前缀和的做法

首先这道题求点双之后每个点就是原来一个环,我们在求点双时记录出每个点双的最小mi和最大标号mx,那么越过[mi,mx]这段区间就是违法的(区间[a,b]越过,即覆盖是指\(a<=mi,b>=mx\)),于是我们对于可以对于每段这种区间记录之前有多少个合法的

最后二分+前缀和搞一搞就好了,但是发现计算之前有多少多少个合法的似乎很难搞...

T1 graph

我们还是点双缩点求出违法区间,同时对于每个坐标求出个\(rb[i]\),表示以\(i\)为左端点,合法区间右端点最远到哪里,怎么求这个?

不知道可不可以log地去做,想了想好像没想到什么好办法.但是这个\(rb[i]\)有个性质就是满足单调的,左边数字的\(rb\)显然不可能大于右边数字的\(rb\)

于是我们可以线性地扫一遍得到\(rb[i]\),对于一个非法区间\([l,r]\)如果左端点在\(l\)的左边(包括l)我们是不可能覆盖到\(r\),我们为了处理方便将其转化成\([l,r-1]\)这样的区间.发现rb值可能会是下图中的情况

一开始我们需要将所有\(rb[i]\)置为\(n\),然后从右往左扫(因为我们的rb值是要取min的,从左往右扫是错误的,可以手动模拟下)得到所有rb值

这样的话对于一个询问\([l,r]\)。根据单调性,我们可以二分找到一个最小的点\(x\)使得\(rb[x]>=r\),同时用前缀和记录\(l\)\(i\)的答案

注意这里的前缀和是指\(i\)\(rb[i]\)这个合法区间内,\(i\)能产生的合法数对贡献之和,我们可以在求\(rb[i]\)的过程中求出

所以由于\([l,x-1]\)中的\(rb[i]\)都小于\(r\)所以是可以直接前缀和计算的,而\(x\)\(r\)这部分都是合法区间直接暴力算就好了

话说这道题求环要么DFS要么用点双,一开始SB地用了边双...因为边双中可能会包含多个环,这样的话小区间就算不到了

然而不知道怎么回事卡死在80分...不知道哪错了

/*
  code by RyeCatcher
*/
const int maxn=600005;
const int inf=0x7fffffff;
int rb[maxn],fa[maxn],dep[maxn];
bool vis[maxn];
int a[maxn];
ll ans[maxn];
struct Edge{
    int ne,to;
}edge[maxn<<1];
int h[maxn],num_edge=1;
int n,m,q;
inline void add_edge(int f,int to){
    edge[++num_edge].ne=h[f];
    edge[num_edge].to=to;
    h[f]=num_edge;
}
int dfn[maxn],low[maxn],st[maxn],tot=0,top=0;
void tarjan(int now,int fa){
    int v;
    st[++top]=now;
    dfn[now]=low[now]=++tot;
    for(ri i=h[now];i;i=edge[i].ne){
        v=edge[i].to;
        if(v==fa)continue;
        if(!dfn[v]){
            tarjan(v,now);
            low[now]=min(low[now],low[v]);
            if(low[v]>=dfn[now]){
                int x=st[top],c=0,mi=inf,mx=-inf;
                do{
                    c++;
                    x=st[top];
                    //printf("--%d ",x);
                    mi=min(mi,x);
                    mx=max(mx,x);
                    top--;  
                }while(x!=v);
                //printf("%d **%d\n",now,c+1);
                c++,mi=min(mi,now),mx=max(mx,now);
                if(c>2)rb[mi]=mx-1;
            }
        }
        else low[now]=min(low[now],dfn[v]);
    }
    return ;
}
int main(){
    int x,y;
    freopen("graph7.in","r",stdin);
    freopen("graph7.ans","w",stdout);
    //FO(graph);
    read(n),read(m);
    for(ri i=1;i<=m;i++){
        read(x),read(y);
        add_edge(x,y);
        add_edge(y,x);
        rb[i]=n;
    }
    for(ri i=m+1;i<=n;i++)rb[i]=n;
    dep[1]=1,fa[1]=0;
    for(ri i=1;i<=n;i++)if(!dfn[i])tarjan(i,0);
    //for(ri i=1;i<=n;i++)printf("--%d %d--\n",i,rb[i]);
    ans[n]=1,rb[n]=n;
    for(ri i=n-1;i>=1;i--){
        rb[i]=min(rb[i+1],rb[i]);
        ans[i]=ans[i+1]+(rb[i]-i+1);
    }
    read(q);
    int l,r,t,mid,L,R;
    //for(ri i=1;i<=n;i++)printf("%d %d %d\n",i,rb[i],ans[i]);
    while(q--){
        read(L),read(R);
        l=L,r=R;
        while(l<=r){
            mid=(l+r)>>1;
            if(rb[mid]<R)l=mid+1;
            else t=mid,r=mid-1;
        }
        //printf("%d %d %d--\n",L,R,t);
        //printf("%d\n",t);
        printf("%llu\n",(ans[L]-ans[t]+1ll*(R-t+2)*1ll*(R-t+1)/2));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Rye-Catcher/p/9841594.html