• 【2019北京集训2】duck 线段树优化建图+tarjan


    题目大意:给你$n$个点,第$i$个点有点权$v_i$。你需要将这$n$个点排成一排,第$i$个点的点权能被累加当且仅当这个点前面存在编号在$[l_i,r_i]$中的点,问你这些点应该如何排列,点权和才能最大。

    数据范围:$n≤10^5$,$1≤v_i≤10^4$。

    这题状压居然给了70分,场上压根没想正解。

    我们不难发现,对于点i,我们连接$l_i→i$,$(l_i+1)→i$,....,$r_i→i$的边,然后跑一个tarjan,缩点后我们得到了一棵树。

    对于每棵树,我们显然只需要减去这棵树树根中最小的点权即可。

    然后这么做显然是$O(n^2)$的,考虑优化一波

    不难发现,这里连边是连向一个区间,我们可以用线段树优化连边,就可以把连边数量降低至log级。

    时间复杂度:$O(nlog n)$

     1 #include<bits/stdc++.h>
     2 #define M 400005
     3 using namespace std;
     4 
     5 struct edge{int u,next;}e[M*30]={0}; int head[M]={0},use=0;
     6 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
     7 int val[M]={0},n;
     8 
     9 int dfn[M]={0},low[M]={0},b[M]={0},d[M]={0},sum[M]={0},minn[M]={0},t=0,cnt=0; stack<int> s;
    10 
    11 struct seg{int l,r,id;}a[M<<2]={0};
    12 int id[M]={0},all=0;
    13 int build(int x,int l,int r){
    14     a[x].l=l; a[x].r=r;
    15     if(l==r) return a[x].id=id[l]=++all;
    16     int mid=(l+r)>>1;
    17     build(x<<1,l,mid); 
    18     build(x<<1|1,mid+1,r);
    19 }
    20 int build2(int x,int l,int r){
    21     if(l==r) return 0; 
    22     int mid=(l+r)>>1;
    23     build2(x<<1,l,mid);
    24     build2(x<<1|1,mid+1,r);
    25     a[x].id=++all;
    26     add(a[x<<1].id,a[x].id);
    27     add(a[x<<1|1].id,a[x].id);
    28 }
    29 
    30 void updata(int x,int l,int r,int ID){
    31     if(l<=a[x].l&&a[x].r<=r){
    32         add(a[x].id,ID);
    33         return;
    34     }
    35     int mid=(a[x].l+a[x].r)>>1;
    36     if(l<=mid) updata(x<<1,l,r,ID);
    37     if(mid<r) updata(x<<1|1,l,r,ID);
    38 }
    39 
    40 void dfs(int x){
    41     dfn[x]=low[x]=++t; b[x]=1; s.push(x);
    42     for(int i=head[x];i;i=e[i].next)
    43     if(!dfn[e[i].u]) dfs(e[i].u),low[x]=min(low[x],low[e[i].u]);
    44     else if(b[e[i].u]) low[x]=min(low[x],dfn[e[i].u]);
    45     if(dfn[x]==low[x]){
    46         int u; cnt++;
    47         do{
    48             u=s.top(); s.pop();
    49             d[u]=cnt; b[u]=0;
    50             if(val[u]!=val[0]){
    51                 sum[cnt]+=val[u]; minn[cnt]=min(minn[cnt],val[u]);
    52             }
    53         }while(u!=x);
    54     }
    55 }
    56 
    57 int main(){
    58     memset(minn,1,sizeof(minn));
    59     memset(val,1,sizeof(val));
    60     scanf("%d",&n);
    61     build(1,1,n);
    62     build2(1,1,n);
    63     for(int i=1;i<=n;i++){
    64         int l,r; scanf("%d%d%d",&l,&r,val+i);
    65         updata(1,l,r,id[i]);
    66     }
    67     for(int i=1;i<=all;i++) if(!dfn[i]) dfs(i);
    68     for(int x=1;x<=all;x++)
    69     for(int i=head[x];i;i=e[i].next)
    70     if(d[e[i].u]!=d[x]) ++b[d[e[i].u]];
    71     int ans=0;
    72     for(int i=1;i<=cnt;i++){
    73         ans+=sum[i];
    74         if(!b[i]) ans-=minn[i];
    75     }
    76     cout<<ans<<endl;
    77 }
  • 相关阅读:
    bzoj2763 [JLOI]飞行路线 分层图最短路
    [模板]分块/可修改莫队 (数颜色种类)
    gcd步数
    洛谷2378 因式分解 字符串
    bzoj1090 字符串折叠
    洛谷1034 NOIP2002 矩形覆盖
    Codeforces#441 Div.2 四*题
    SPFA的小优化
    洛谷1073 NOIP2009 最优贸易
    bzoj2100 [Usaco2010 DEC]Apple Delivery苹果贸易
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10646589.html
Copyright © 2020-2023  润新知