[loj3277]星座3

如果不合法,利用贪心发现当且仅当某两个星星所构成的矩形中没有白点

反过来,考虑留下若干个星星,那么即要求留下的星星两两之间满足:$\max_{x_{1}\le i\le x_{2}}a_{i}\ge \min(y_{1},y_{2})$

考虑笛卡尔树,那么在笛卡尔树上这等价于使得两点lca的高度大于等于两点最低高度,由于$a_{fa}\ge a_{k}$($fa$为$k$在lca上的父亲),因此这又等价于要求以$k$为根的子树中最多只能保留1个数比$a_{k}$大

令$f[i][j]$表示以$i$为根的子树中最高不超过为$j$且合法的最大保留的价值,其合法状态数量为不超过子树中点数量,因此启发式合并即可维护,时间复杂度为$o(n\log^{2}n)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 200005
 4 #define ll long long
 5 set<pair<ll,ll> >::iterator it;
 6 set<pair<ll,ll> >s[N];
 7 int n,m,x,y,z,a[N],st[N],ls[N],rs[N],f[N];
 8 long long ans,mx[N],tag[N];
 9 int find(int k){
10     if (k==f[k])return k;
11     return f[k]=find(f[k]);
12 }
13 void merge(int x,int y,int k){
14     x=find(x),y=find(y);
15     while ((s[y].size())&&((*s[y].begin()).first<=k)){
16         mx[y]=max(mx[y],(*s[y].begin()).second+tag[y]);
17         s[y].erase(s[y].begin());
18     }
19     if (s[x].size()<s[y].size()){
20         f[x]=y;
21         swap(x,y);
22     }
23     tag[x]+=mx[y];
24     tag[y]+=mx[x];
25     mx[x]+=mx[y];
26     for(it=s[y].begin();it!=s[y].end();it++)
27         s[x].insert(make_pair((*it).first,(*it).second+tag[y]-tag[x]));
28 }
29 void dfs(int k){
30     if (!k)return;
31     dfs(ls[k]);
32     dfs(rs[k]);
33     merge(k,ls[k],a[k]);
34     merge(k,rs[k],a[k]);
35 }
36 int main(){
37     scanf("%d",&n);
38     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
39     for(int i=1;i<=n;i++)f[i]=i;
40     for(int i=1;i<=n;i++){
41         while ((st[0])&&(a[st[st[0]]]<a[i]))ls[i]=st[st[0]--];
42         if (st[0])rs[st[st[0]]]=i;
43         st[++st[0]]=i;
44     }
45     scanf("%d",&m);
46     for(int i=1;i<=m;i++){
47         scanf("%d%d%d",&x,&y,&z);
48         s[x].insert(make_pair(y,z));
49         ans+=z;
50     }
51     dfs(st[1]);
52     x=find(st[1]);
53     for(it=s[x].begin();it!=s[x].end();it++)mx[x]=max(mx[x],tag[x]+(*it).second);
54     printf("%lld",ans-mx[x]);
55 } 
View Code

 

posted @ 2020-10-25 21:17  PYWBKTDA  阅读(141)  评论(0编辑  收藏  举报