C. Destroying Array ###K //K

题目链接:https://codeforces.ml/contest/722/problem/C

题意:给定 一个数组,查询每次删除掉某个位置后 最大的子区间和为多少

思路: 可以用线段树维护区间最大值做,每次只需要单点删除, 注意别爆ll

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define pb push_back
 5 const int maxn =1e5+10;
 6 const int mod=1e9+7;
 7 int a[maxn];
 8 int p[maxn];
 9 
10 struct ac
11 {
12     int l,r;
13     ll max1,suf,pre,sum;
14     void update(ll v)
15     {
16         max1=pre=suf=sum=v;
17     }
18 };
19 ac tree[maxn*4];
20 
21 void pushup(int x)
22 {
23     if(tree[x<<1].sum+tree[x<<1|1].sum>=0)
24         tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum;
25     else
26         tree[x].sum=-1e18;
27     tree[x].max1=max({tree[x<<1].max1,tree[x<<1|1].max1,tree[x<<1].suf+tree[x<<1|1].pre});
28     tree[x].pre=max(tree[x<<1].pre,tree[x<<1].sum+tree[x<<1|1].pre);
29     tree[x].suf=max(tree[x<<1|1].suf,tree[x<<1].suf+tree[x<<1|1].sum);
30 }
31 
32 void build(int x,int l,int r)
33 {
34     tree[x].l=l,tree[x].r=r;
35     if(l==r)
36     {
37         tree[x].update(a[l]);
38     }
39     else
40     {
41         int mid=(l+r)/2;
42         build(x<<1,l,mid);
43         build(x<<1|1,mid+1,r);
44         pushup(x);
45     }
46 }
47 
48 void update(int x,int pos,ll v)
49 {
50     int L=tree[x].l,R=tree[x].r;
51     if(L==R)
52     {
53         tree[x].update(v);
54     }
55     else
56     {
57         int mid=(L+R)/2;
58         if(pos<=mid) update(x<<1,pos,v);
59         if(pos>mid) update(x<<1|1,pos,v);
60         pushup(x);
61     }
62 }
63 
64 
65 int main()
66 {
67     ios::sync_with_stdio(false);
68     cin.tie(0);
69     int n;
70     cin>>n;
71     for(int i=1;i<=n;i++)
72     {
73         cin>>a[i];
74     }
75     for(int i=1;i<=n;i++)
76     {
77         cin>>p[i];
78     }
79 
80     build(1,1,n);
81     //cout<<tree[1].max1<<" 2"<<'\n';
82     for(int i=1;i<=n;i++)
83     {
84         update(1,p[i],-1e18);
85         cout<<max(0ll,tree[1].max1)<<'\n';
86     }
87 
88 
89 
90 
91 
92 
93 }
View Code

也可以用并查集做, 用并查集的话要反向考虑 把删除操作转化成添加操作来考虑 然后每次和左右两边的合并即可

 1 #include <bits/stdc++.h>
 2 #define double long double
 3 #define lb long double
 4 #define ll long long
 5 #define pi pair<int,int>
 6 #define fi first
 7 #define sc second
 8 #define pb push_back
 9 using namespace std;
10 const int maxn=1e5+10;
11 
12 ll sum[maxn];
13 int f[maxn];
14 int n;
15 int c[maxn];
16 int st[maxn];
17 
18 int find1(int x)
19 {
20     if(x==f[x]) return x;
21     return f[x]=find1(f[x]);
22 }
23 
24 
25 
26 int main()
27 {
28     ios::sync_with_stdio(0);
29     cin.tie(0);
30     cin>>n;
31     for(int i=1;i<=n;i++) cin>>sum[i],f[i]=i;
32     for(int i=1;i<=n;i++) cin>>c[i];
33     ll mx=0;
34     vector<ll>ans;
35     for(int i=n;i>=1;i--)
36     {
37         ans.pb(mx);
38         int x=c[i];
39         int l=x-1,r=x+1;
40         int t=find1(x);
41         st[x]=1;
42         if(l>=1&&st[l])
43         {
44             int tl=find1(l);
45             f[tl]=t;
46             sum[t]+=sum[tl];
47         }
48         if(r<=n&&st[r])
49         {
50             int tr=find1(r);
51             f[tr]=t;
52             sum[t]+=sum[tr];
53         }
54         mx=max(mx,sum[t]);
55     }
56     reverse(ans.begin(),ans.end());
57     for(auto &v:ans) cout<<v<<'\n';
58 
59 
60 
61 
62 }
View Code

 

posted @ 2020-11-04 19:01  canwinfor  阅读(93)  评论(0)    收藏  举报