【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(n\log\ 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 }

猜你喜欢

转载自www.cnblogs.com/xiefengze1/p/10646589.html
今日推荐