1. 程式人生 > >280D k-Maximum Subsequence Sum(區間最大k段和)(線段樹 + 最大子段和 + 區間修改 + 區間查詢 + 單點修改)

280D k-Maximum Subsequence Sum(區間最大k段和)(線段樹 + 最大子段和 + 區間修改 + 區間查詢 + 單點修改)

題目

題意

給定n個數的序列,定義兩個操作
0kval 把序列第k個數的值變為val
1lrk 詢問在區間 AlAr 中,選取 m 段不相交的子區間,使得這 m 段子區間的和最大,其中0mk

思路

首先這裡講了如何解決 k=1 的情況,即用線段樹維護並進行合併 blablabla....
然後考慮如何取k段,我們只需要去給定區間取 k 次區間最大子段和,累加答案後,對取出的區間做區間取反操作。而當所取的區間最大子段和小於 0 的時候,則跳出不計
做法的正確性可以從貪心或者費用流的思想上證明
之後再進行單點修改就行了

那麼實現的就在維護的是maxs,maxr,maxl 這三個值的時候,如何進行取反操作,如何在找出 maxs 的同時記錄下,對應的哪一段區間。(這三個變數的含義見區間最大子段和部分)
而取反實際上就是將最大子段和以及最小子段和進行了交換,而我們只需要同時維護最大子段和最小子段和,記錄下對應的區間資訊,在取反操作時對調就可以了。而又由於我們的 maxs 是用 maxr,maxl來維護的,所有後兩者的區間資訊也需要記錄

於是就有了這麼一個維護了18個值的線段樹…
sum 區間和 [l,r] 區間的左右邊界

maxs 最大子段和 [maxsl,maxsr] 最大子段和的左右邊界
mins 最小子段和 [maxsl,maxsr] 最小子段和的左右邊界
maxl 最大字首和 maxlp 最大字首和的右邊界
minl 最小字首和 minlp 最小字首和的右邊界
maxr 最大字尾和 maxrp 最大字尾和的左邊界
minr 最小字尾和 minrp 最小字尾和的左邊界
tag 區間取反標記

然後將區間合併更新所有的最佳情況函式化為了

merge()
又由於使用了 merge,所以 tag 需要在 merge 前記錄一下並賦值

其他的就是基本的線段樹的操作了

程式碼

#include <bits/stdc++.h>
using namespace std;
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define pd(n) printf("%d\n", (n))
#define pdd(n,m) printf("%d %d", n, m)
#define pld(n) printf("%lld\n", n)
#define pldd(n,m) printf("%lld %lld\n", n, m)
#define sld(n) scanf("%lld",&n)
#define sldd(n,m) scanf("%lld%lld",&n,&m)
#define slddd(n,m,k) scanf("%lld%lld%lld",&n,&m,&k)
#define sf(n) scanf("%lf",&n)
#define sff(n,m) scanf("%lf%lf",&n,&m)
#define sfff(n,m,k) scanf("%lf%lf%lf",&n,&m,&k)
#define ss(str) scanf("%s",str)
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define mm(a,n) memset(a, n, sizeof(a))
#define debug(x) cout<<#x<<": "<<x<<endl
#define pb push_back
#define mk make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const ll mod = 1000000007;
const double eps = 1e-9;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+5;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
template<typename T>inline void read(T &x){
    T f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    x*=f;
}
// head

struct Node {
    int l, r;
    int sum, tag;
    int maxs, maxl, maxr;
    int maxsl, maxsr, minsl, minsr;
    int maxlp, maxrp, minlp, minrp;
    int mins, minl, minr;
} tree[maxn<<2];
int num[maxn];

Node merged(Node ls, Node rs){
    Node ret;
    ret.sum = ls.sum + rs.sum;
    ret.l = ls.l;
    ret.r = rs.r;
    ret.tag = 0;
    if(ls.maxs > rs.maxs){
        ret.maxs  = ls.maxs;
        ret.maxsl = ls.maxsl;
        ret.maxsr = ls.maxsr;
    }
    else {
        ret.maxs  = rs.maxs;
        ret.maxsl = rs.maxsl;
        ret.maxsr = rs.maxsr;
    }
    if(ret.maxs < ls.maxr + rs.maxl) {
        ret.maxs  = ls.maxr + rs.maxl;
        ret.maxsl = ls.maxrp;
        ret.maxsr = rs.maxlp;
    }

    if(ls.maxl > ls.sum + rs.maxl){
        ret.maxl  = ls.maxl;
        ret.maxlp = ls.maxlp;
    }
    else{
        ret.maxl  = ls.sum + rs.maxl;
        ret.maxlp = rs.maxlp;
    }

    if(rs.maxr > rs.sum + ls.maxr){
        ret.maxr  = rs.maxr;
        ret.maxrp = rs.maxrp;
    }
    else {
        ret.maxr  = rs.sum + ls.maxr;
        ret.maxrp = ls.maxrp;
    }

    if(ls.mins < rs.mins){
        ret.mins  = ls.mins;
        ret.minsl = ls.minsl;
        ret.minsr = ls.minsr;
    }
    else {
        ret.mins  = rs.mins;
        ret.minsl = rs.minsl;
        ret.minsr = rs.minsr;
    }
    if(ret.mins > ls.minr + rs.minl) {
        ret.mins  = ls.minr + rs.minl;
        ret.minsl = ls.minrp;
        ret.minsr = rs.minlp;
    }

    if(ls.minl < ls.sum + rs.minl){
        ret.minl  = ls.minl;
        ret.minlp = ls.minlp;
    }
    else{
        ret.minl  = ls.sum + rs.minl;
        ret.minlp = rs.minlp;
    }

    if(rs.minr < rs.sum + ls.minr){
        ret.minr  = rs.minr;
        ret.minrp = rs.minrp;
    }
    else {
        ret.minr  = rs.sum + ls.minr;
        ret.minrp = ls.minrp;
    }

    return ret;
}

void inv(int i){
    tree[i].sum = -tree[i].sum;
    tree[i].tag ^= 1;
    swap(tree[i].maxs, tree[i].mins);
    swap(tree[i].maxsl, tree[i].minsl);
    swap(tree[i].maxsr, tree[i].minsr);
    tree[i].maxs = -tree[i].maxs; tree[i].mins = -tree[i].mins;

    swap(tree[i].maxl, tree[i].minl);
    swap(tree[i].maxlp, tree[i].minlp);
    tree[i].maxl = -tree[i].maxl
            
           

相關推薦

280D k-Maximum Subsequence Sum區間k線段 + 大子 + 區間修改 + 區間查詢 + 修改

題目 題意 給定nn個數的序列,定義兩個操作 ⋅0kval⋅0kval 把序列第k個數的值變為val ⋅1lrk⋅1lrk 詢問在區間 Al⋯ArAl⋯Ar 中,選取 mm 段不相交的子區間,使得這 mm 段子區間的和最大,其中0≤m≤k0≤m≤k。

【BZOJ3638】Cf172 k-Maximum Subsequence Sum 線段區間合並模擬費用流

font uil sin upper sample dex else name etc 【BZOJ3638】Cf172 k-Maximum Subsequence Sum Description 給一列數,要求支持操作: 1.修改某個數的值 2.讀入l,r,k,詢問

【bzoj3638】Cf172 k-Maximum Subsequence Sum 模擬費用流+線段區間合並

light 最大連續 範圍 區間和 data while define query lmin 題目描述 給一列數,要求支持操作: 1.修改某個數的值 2.讀入l,r,k,詢問在[l,r]內選不相交的不超過k個子段,最大的和是多少。 輸入 The fi

BZOJ.3638.CF172 k-Maximum Subsequence Sum(模擬費用流 線段)

() sum 一個 新增 query freopen tdi int 取反 題目鏈接 各種zz錯誤。。簡直要寫瘋 /* 19604kb 36292ms 樸素線段樹:線段樹上每個點維護O(k)個信息,區間合並時O(k^2),總O(mk^2logn)->GG 考慮費用流

【BZOJ3638】k-Maximum Subsequence Sum

【題目連結】 【五倍經驗連結】 【思路要點】 容易發現一種可行的費用流建邊。 用線段樹模擬上述費用流,我們需要實現查詢區間最大子段和和區間取反。 時間複雜度O(MKLogN)O(MKLogN)。 【程式碼】

CF280D k-Maximum Subsequence Sum 線段

題目大意: 給你一個長度為n(1<=n<=105)n(1<=n<=105)的序列,支援兩種操作: 1.修改某個位置的值。 2.在區間[l,r][l,r]裡選擇不超過k(1<=k<=20)k(1<=k<=20)

【CF280D】 k-Maximum Subsequence Sum線段模擬費用流

line 最大 operator 優優 理解 modify pushd 關於 做的 昨天考試被教育了一波。為了學習一下\(T3\)的科技,我就找到了這個遠古時期的\(cf\)題(雖然最後\(T3\)還是不會寫吧\(QAQ\)) 顧名思義,這個題目其實可以建成一個費用流的模型

1007 Maximum Subsequence Sum25 分連續子序列

題意:求最大連續子序列和並記錄該序列的頭尾元素 #include <bits/stdc++.h> using namespace std; int N; int main() { cin>>N; vector<int>

01-複雜度2 Maximum Subsequence Sum大子問題變化

一、題目: 01-複雜度2 Maximum Subsequence Sum (25 分) Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuous subsequence is de

PAT 1007 Maximum Subsequence Sum大子

原題地址 求出給定數字串的最大子串和,以及這個最大子串和的首尾元素。(若有多個最大子串則取最靠左的那個) 解題思路 本題基本上是最大子串和的裸題,只是增加了一個輸出首尾元素的要求。

PAT甲級--1007 Maximum Subsequence Sum (25)25 分大子序列及其起始終點】

1007 Maximum Subsequence Sum (25)(25 分) Given a sequence of K integers { N~1~, N~2~, ..., N~K~ }. A continuous subsequence is defined to

資料結構學習筆記1Maximum Subsequence Sum大子

問題思路分析:就是課堂上所講過的最大子列和問題,不過需要輸出子列頭和尾的項根據網上的資料,摹寫程式碼為具體實現:#include<iostream> using namespace std; int main (){ int N ; cin >>

PAT Maximum Subsequence Sum[大子序列,簡單dp]

ace 序號 fin nts 很好 lag malle test 二次 1007 Maximum Subsequence Sum (25)(25 分) Given a sequence of K integers { N~1~, N~2~, ..., N~K~ }.

1007 Maximum Subsequence Sum - 連續子序

思路: 原則是:用now表示當前的判斷,在把多個元素加和的時候,若加到a[i]的時候小於0,那麼捨去a[i],繼續向後判斷,設ans=-1記錄最大值(設為-1的原因是要處理0開頭的情況) 若sum==0那麼我們不要(題上要求i,j最小),但如果第1個數是0那麼就要 用tleft表示臨時的

1007 Maximum Subsequence Sum 25 point(s)

 1007 Maximum Subsequence Sum (25 point(s)) 部分未通過 22分 #include<iostream> #include<vector> #include<algorithm> using namespa

1007 Maximum Subsequence Sum 25 分

1007 Maximum Subsequence Sum (25 分) Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuou

PAT--1007 Maximum Subsequence Sum 25 分

1007 Maximum Subsequence Sum (25 分) Given a sequence of K integers { N​1, N​2​​ , …, N,​K ​​ }. A continuous subsequence is defined to be { N​

01-複雜度2 Maximum Subsequence Sum25 分

Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuous subsequence is defined to be { N​i​​, N​i+1​​, ..., N​j​​ } wher

1007 Maximum Subsequence Sum25 分PAT甲級

Problem Description: Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuous subsequence is defined to be { N​i​​, N​i+

PTA 01-複雜度2 Maximum Subsequence Sum 25 分

01-複雜度2 Maximum Subsequence Sum (25 分) Given a sequence of K integers { N​1​​, N​2​​, …, N​K​​ }. A continuous subsequence is defin