zoukankan      html  css  js  c++  java
  • noiac26 T1 (并查集)

    考虑计算每个位置的数作为最小值时有多少种情况

    方便起见,以位置为第二关键字比较大小,这样就不会出现“相同的”数

    可以方便地计算出以i位置为最小值的区间端点的可行位置:[A,i],[i,B]

    这是我选的一个区间,那么另一个区间会有两种情况:在[A,B]的范围内或者不在

    不妨只考虑另一个区间在i这个区间的右边的情况,设这另一个区间是[l,r]

    这种时候第一个区间的左端点是在[A,i]随便选的

    第一种情况:

      如果l<=B,那么r显然也<=B,所以i<=第一个区间的右端点<l<=r<=B,发现方案数只与[i,B]这个区间的长度有关,可以由公式算出,或者是提前预处理推出

    第二种情况:

      如果l>B,我还要保证[l,r]内的所有数都大于a[i],这种情况和第一个区间绝对不相交,所以第一个区间的右端点也可以随便选。可以用树状数组维护左端点>x的可选的区间个数

    那么我可以按照数字从大到小做,给每个位置维护一个并查集,表示从这个点可延伸出的最远的端点(在这个范围内的数都>=now)

    这样,A和B也就顺便算出来了

     1 #include<bits/stdc++.h>
     2 #define CLR(a,x) memset(a,x,sizeof(a))
     3 #define MP make_pair
     4 using namespace std;
     5 typedef long long ll;
     6 typedef unsigned long long ull;
     7 typedef pair<int,int> pa;
     8 const int maxn=2e5+10,P=1e9+7;
     9 
    10 inline ll rd(){
    11     ll x=0;char c=getchar();int neg=1;
    12     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
    13     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    14     return x*neg;
    15 }
    16 
    17 int N,l[maxn],r[maxn],a[maxn],ori[maxn];
    18 int stk[maxn],sh,rnk[maxn],tr[2][maxn];
    19 pa tmp[maxn];
    20 struct Node{
    21     int f,l,r;
    22 }nd[maxn];
    23 vector<int> pos[maxn];
    24 int ans,c3[maxn];
    25 bool flag[maxn];
    26 
    27 
    28 inline int lowbit(int x){return x&(-x);}
    29 inline void add(int i,int x,int y){
    30     for(;x<=N;x+=lowbit(x)) tr[i][x]+=y,tr[i][x]%=P;
    31 }
    32 inline int query(int i,int x){
    33     int re=0;for(;x;x-=lowbit(x)) re+=tr[i][x],re%=P;return re;
    34 }
    35 
    36 inline int getf(int x){return x==nd[x].f?x:nd[x].f=getf(nd[x].f);}
    37 
    38 inline void change(int l,int r,int d){
    39     int n=1ll*(r-l+1)*(r-l+2)/2%P;
    40     add(0,l,d*n),add(1,r,d*n);
    41 }
    42 
    43 inline void uni(int x){
    44     flag[x]=1;nd[x].l=nd[x].r=x;
    45     int a=0,b=0;
    46     if(flag[x-1]) a=getf(x-1);
    47     if(flag[x+1]) b=getf(x+1);
    48     if(a){
    49         nd[a].f=x;
    50         change(nd[a].l,nd[a].r,-1);
    51         nd[x].l=nd[a].l;
    52     }if(b){
    53         nd[b].f=x;
    54         change(nd[b].l,nd[b].r,-1);
    55         nd[x].r=nd[b].r;
    56     }
    57     change(nd[x].l,nd[x].r,1);
    58 }
    59 
    60 int main(){
    61     //freopen("","r",stdin);
    62     int i,j,k;
    63     N=rd();
    64     c3[2]=1;
    65     for(i=3;i<=N;i++) c3[i]=(c3[i-1]+1ll*i*(i-1)/2)%P;
    66     for(i=1;i<=N;i++) ori[i]=a[i]=rd(),tmp[i]=MP(a[i],i),r[i]=N,l[i]=1;
    67     sort(tmp+1,tmp+N+1);
    68     for(i=1;i<=N;i++)
    69         a[i]=lower_bound(tmp+1,tmp+N,MP(a[i],i))-tmp,pos[a[i]].push_back(i);
    70     for(i=1;i<=N;i++) nd[i].f=i;
    71 
    72     for(i=N;i;i--){
    73         int x=tmp[i].second;
    74         uni(x);
    75         int f=getf(x),l=nd[f].l,r=nd[f].r;
    76         ans+=1ll*(x-l+1)*(c3[r-x+1]+1ll*(r-x+1)*(query(0,N)-query(0,r+1))%P)%P*ori[x]%P,ans%=P;
    77         ans+=1ll*(r-x+1)*(c3[x-l+1]+1ll*(x-l+1)*query(1,l-1)%P)%P*ori[x]%P,ans%=P;
    78     }
    79 
    80     printf("%d
    ",(ans+P)%P);
    81     return 0;
    82 }
  • 相关阅读:
    160809322-王翔君第十一次c语言作业
    c语言第九次作业
    王翔君第9次c语言作业
    王翔君160809322第六次作业
    160809322-王翔君第四次作业
    第三次作业160809322
    160809322-王翔君
    160809322-王翔君
    输出不可重复的质因数
    求最大数与最小数乘积
  • 原文地址:https://www.cnblogs.com/Ressed/p/10066367.html
Copyright © 2011-2022 走看看