zoukankan      html  css  js  c++  java
  • CF901C Bipartite Segments[点双+二分+前缀优化]

    不想翻译了,直接放luogu翻译


    说了没有偶环,也就是说全是奇环,再结合二分图性质,那么暴力的话,固定左端点,增大序号,加点直到产生环就不合法了。也就是说,任何一个环,只要他上面的数全都被加了,就不合法了,那么,环上的数若最大$ ext{m2}$,最小$ ext{m1}$,那么如果当前枚举的子区间$xle m1且yge m2$,那就不合法了。这样,我们可以转化一下问题,给一堆区间,然后每次问$[L,R]$有多少子区间不合法(即存在一个给定的区间被这个子区间覆盖了),然后总方案数减去不合法数。但是还存在两个问题。

    一,上述的环有多少个?怎么找?发现所有环都是奇环,任何两个奇环不能相交或者公用边,因为这些情况都会附带再产生一个偶环(结论源自于手动模拟),与题意矛盾。所以,每条边最多属于一个简单的奇环。那么,这就是一个仙人掌。。所以,可以证出,环是相互独立的,并且不会超过$M/3$个。这样,就可以接受了,这些环通过点连接,可以看成是一堆点双连接,我们直接tarjan找点双,每个点双对应到区间上即可。

    二,区间询问怎么做?`````假设左端点$x$,那么右端点向右开始挪,当不合法(也就是区间被覆盖了)的时候后面都不合法了。再看以$x-1$为左端点,首先不合法的右端点只会比$x$的小。。所以,我们维护这样一个$rb_i$表示最早找到的一个右端点使得这个区间$[i,rb_i]$覆盖了某给定区间,那么他是单调不减的(就是上面这个说明)。那么,为了计算所有不合法子区间,只要计算$sumlimits_{iin [l,r],rb_ile r}(r-rb_i+1)=(x-l+1)(r+1)-sumlimits_{i=l}^{x}rb_i$。这里的$x$是最靠右的$i$,且$iin [l,r],rb_ile r$。为了找到$x$,利用上述$rb$单调性质,直接二分查找即可。sum的部分可以直接前缀和预处理。然后即可快速计算答案。

    有关仙人掌的坑。。有空再补。。虽然这题似乎和仙人掌没啥太大关系

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define mst(x) memset(x,0,sizeof x)
     8 #define dbg(x) cerr << #x << " = " << x <<endl
     9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 typedef pair<int,int> pii;
    14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    19 template<typename T>inline T read(T&x){
    20     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    21     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    22 }
    23 const int N=3e5+7;
    24 struct thxorz{
    25     int to[N<<1],nxt[N<<1],head[N],tot;
    26     inline void add(int x,int y){
    27         to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
    28         to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
    29     }
    30 }G;
    31 ll sum[N];
    32 int n,m,q,L,R,l,r;
    33 int rb[N];
    34 #define y G.to[j]
    35 int dfn[N],low[N],tim,stk[N],Top,rt;
    36 void tarjan(int x){//dbg(x);
    37     dfn[x]=low[x]=++tim;
    38     if(rt==x&&!G.head[x])return;
    39     stk[++Top]=x;
    40     for(register int j=G.head[x];j;j=G.nxt[j]){
    41         if(!dfn[y]){
    42             tarjan(y),MIN(low[x],low[y]);
    43             if(low[y]>=dfn[x]){
    44                 int tmp,mi=n+1,ma=0,cnt=0;
    45                 do MIN(mi,tmp=stk[Top--]),MAX(ma,tmp),++cnt;while(tmp^y);
    46                 MIN(mi,x),MAX(ma,x),++cnt;//dbg2(mi,ma);
    47                 if(cnt>2)MIN(rb[mi],ma);
    48             }
    49         }
    50         else MIN(low[x],dfn[y]);
    51     }
    52 }
    53 #undef y
    54 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    55     read(n),read(m);
    56     for(register int i=1,x,y;i<=m;++i)read(x),read(y),G.add(x,y);
    57     fill(rb+1,rb+n+1,n+1);
    58     for(register int i=1;i<=n;++i)if(!dfn[i])Top=0,tarjan(i);
    59     for(register int i=n-1;i;--i)MIN(rb[i],rb[i+1]);//dbg2(i,rb[i]);
    60     for(register int i=1;i<=n;++i)sum[i]=sum[i-1]+rb[i];
    61     read(q);for(register int i=1,L,R,mid;i<=q;++i){
    62         l=read(L),r=read(R);--L;
    63         while(L<R){
    64             mid=L+R+1>>1;
    65             if(rb[mid]<=r)L=mid;
    66             else R=mid-1;
    67         }//dbg(L);
    68         printf("%I64d
    ",(r-l+2)*1ll*(r-l+1)/2-((L-l+1)*1ll*(r+1)-(sum[L]-sum[l-1])));
    69     }
    70     return 0;
    71 }
    View Code

    总结:主要在问题二上卡住了。主要还是考虑从暴力入手,因为这个子区间问题基本思路就是固定左端点,算右端点,因为这题有两个单调的地方,所以可以用前缀和优化。

  • 相关阅读:
    Hadoop2.2.0 注意事项
    为一个表增加一列,这个列能够自增加1
    商品推荐系统问题
    Android Service服务-(转)
    android实现通知栏消息
    【Android】状态栏通知Notification、NotificationManager详解(转)
    android调用邮件应用发送email
    有关WebView开发问题(转)
    Android开发把项目打包成apk-(转)
    对话框(单选)
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11727802.html
Copyright © 2011-2022 走看看