0
点赞
收藏
分享

微信扫一扫

2022/2/5

小美人鱼失去的腿 2022-02-05 阅读 27
c++算法

p6242 线段树区间最大值 历史最大值 最小值操作,区间求和混合模板

思路没大懂,但代码理解了。。。

题解 P6242 【【模板】线段树 3】 - ​ - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}

int n,m,op,l,r,k;
struct tree{
    ll sum;
    int add_a,add_a1,add_b,add_b1;
    int l,r,maxa,se,maxb,cnt;
}tree[2000005];
void push_up(int p){
    tree[p].maxa=max(tree[p<<1].maxa,tree[p<<1|1].maxa);
    tree[p].maxb=max(tree[p<<1].maxb,tree[p<<1|1].maxb);
    tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
    if(tree[p<<1].maxa==tree[p<<1|1].maxa){
        tree[p].se=max(tree[p<<1].se,tree[p<<1|1].se);
        tree[p].cnt=tree[p<<1].cnt+tree[p<<1|1].cnt;
    }
    if(tree[p<<1].maxa>tree[p<<1|1].maxa){
        tree[p].se=max(tree[p<<1].se,tree[p<<1|1].maxa);
        tree[p].cnt=tree[p<<1].cnt;
    }
    if(tree[p<<1].maxa<tree[p<<1|1].maxa){
        tree[p].se=max(tree[p<<1].maxa,tree[p<<1|1].se);
        tree[p].cnt=tree[p<<1|1].cnt;
    }
}
void build(int l,int r,int p){
    tree[p].l=l,tree[p].r=r;
    if(l==r){
        tree[p].sum=tree[p].maxa=tree[p].maxb=read();
        tree[p].se=-1e9;
        tree[p].cnt=1;
        return;
    }
    int mid=l+r>>1;
    build(l,mid,p<<1);
    build(mid+1,r,p<<1|1);
    push_up(p);
}
void update(int k1,int k2,int k3,int k4,int p){
    tree[p].sum+=1ll*k1*tree[p].cnt+1ll*k3*(tree[p].r-tree[p].l+1-tree[p].cnt);
    tree[p].maxb=max(tree[p].maxb,tree[p].maxa+k2);
    tree[p].add_b=max(tree[p].add_b,tree[p].add_a+k2);
    tree[p].add_b1=max(tree[p].add_b1,tree[p].add_a1+k4);
    tree[p].maxa+=k1,tree[p].add_a+=k1;
    tree[p].add_a1+=k3;
    if(tree[p].se!=-1e18) tree[p].se+=k3;
}
void push_down(int p){
    int maxn=max(tree[p<<1].maxa,tree[p<<1|1].maxa);
    if(tree[p<<1].maxa==maxn)
        update(tree[p].add_a,tree[p].add_b,tree[p].add_a1,tree[p].add_b1,p<<1);
    else update(tree[p].add_a1,tree[p].add_b1,tree[p].add_a1,tree[p].add_b1,p<<1);
    if(tree[p<<1|1].maxa==maxn)
        update(tree[p].add_a,tree[p].add_b,tree[p].add_a1,tree[p].add_b1,p<<1|1);
    else update(tree[p].add_a1,tree[p].add_b1,tree[p].add_a1,tree[p].add_b1,p<<1|1);
    tree[p].add_a=tree[p].add_a1=tree[p].add_b=tree[p].add_b1=0;
}
void update_add(int p){
    if(tree[p].l>r||tree[p].r<l) return;
    if(l<=tree[p].l&&tree[p].r<=r) return update(k,k,k,k,p);
    push_down(p);
    update_add(p<<1),update_add(p<<1|1);
    push_up(p);
}
void update_min(int p){
    if(tree[p].l>r||tree[p].r<l||k>=tree[p].maxa) return;
    if(l<=tree[p].l&&tree[p].r<=r&&k>tree[p].se)
    return update(k-tree[p].maxa,k-tree[p].maxa,0,0,p);
    push_down(p);
    update_min(p<<1),update_min(p<<1|1);
    push_up(p);
}
ll query_add(int p){
    if(tree[p].l>r||tree[p].r<l) return 0;
    if(l<=tree[p].l&&tree[p].r<=r) return tree[p].sum;
    push_down(p);
    return query_add(p<<1)+query_add(p<<1|1);
}
int query_maxa(int p){
    if(tree[p].l>r||tree[p].r<l) return -1e9;
    if(l<=tree[p].l&&tree[p].r<=r) return tree[p].maxa;
    push_down(p);
    return max(query_maxa(p<<1),query_maxa(p<<1|1));
}
int query_maxb(int p){
    if(tree[p].l>r||tree[p].r<l) return -1e9;
    if(l<=tree[p].l&&tree[p].r<=r) return tree[p].maxb;
    push_down(p);
    return max(query_maxb(p<<1),query_maxb(p<<1|1));
}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();m=read();
    build(1,n,1);
    while(m--){
        op=read(),l=read(),r=read();
        if(op==1) k=read(),update_add(1);
        if(op==2) k=read(),update_min(1);
        if(op==3) cout<<query_add(1)<<endl;
        if(op==4) cout<<query_maxa(1)<<endl;
        if(op==5) cout<<query_maxb(1)<<endl;
    }
    return 0;
}

p1198 rmq区间最值

查询还是那样查询,变得是如何添加数,如果加一次我们就要重新dp一次的话那太浪费时间了,其实我们只要更新那些重点是n的区间就可以了;即i+(1<<j)-1=n==>i=n-(1<<j)+1;

然后去枚举每个j就可以了

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
ll n,m,d,t,dp[200005][32],L;
char c;
void change(ll x){
    dp[n][0]=x;
    for(int j=1;(1<<j)<=n;j++){
        ll i=n-(1<<j)+1;//i代表需要更新的区间的起点
        dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
    }
}
ll rmq(ll l){
    int k=log2(n-l+1);
    return max(dp[l][k],dp[n-(1<<k)+1][k]);
}
int main(){
   // freopen("in.txt","r",stdin);
    cin>>m>>d;
    while(m--){
        cin>>c>>L;
        if(c=='A'){
            n++;
            change((t+L)%d);
        }
        else{
            t=rmq(n-L+1);
            cout<<t<<endl;
        }
    }
    return 0;
}

p1774 树状数组求逆序对

树状数组(求逆序对)_卑鄙的我-CSDN博客_树状数组求逆序对

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
ll n,t[500005]={0},ans=0;
struct nx{
    ll v,id;
}a[500005];
bool cmp(nx a,nx b){
    if(a.v==b.v) return a.id>b.id;//按照一开始输入时的顺序排
    return a.v>b.v;
}
void update(ll x){
    for(int i=x;i<=n;i+=lowbit(i))
    t[i]++;
}
ll getsum(int x){
    ll res=0;
    for(int i=x;i;i-=lowbit(i))
        res+=t[i];
    return res;
}
int main(){
    //freopen("in.txt","r",stdin);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i].v,a[i].id=i;
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        update(a[i].id);
        ans+=(getsum(a[i].id-1));//因为是按照第几个大来排的顺序,所以这是在求正序对
    }
    cout<<ans<<endl;
    return 0;
}

p1883 三分

三分好像和二分差不了多少,,二分适合单调序列而三分适合凸性的函数序列,比如而二次函数那种,也就是多了个mid

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
int t,n;
struct fx{
    double a,b,c;
}f[10005];
double check(double x){
    double res=-1e9;
    for(int i=1;i<=n;i++)
        res=max(res,f[i].a*x*x+f[i].b*x+f[i].c);
    return res;
}
int main(){
    //freopen("in.txt","r",stdin);
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;i++) cin>>f[i].a>>f[i].b>>f[i].c;
        double l=0,r=1000,m1,m2;
        while(l+eps<r){
            m1=l+(r-l)/3.0;
            m2=r-(r-l)/3.0;
            if(check(m1)>check(m2)) l=m1;
            else r=m2;
        }
        printf("%.4f\n",check(l));
    }
    return 0;
}

p1886 单调队列模板

题解 P1886 【滑动窗口】 - hankeke 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(ll a,ll b){return a>b;}
int n,k;
struct hd1{
    int v,id;
    bool operator<(const hd1 &a)const{
    return v>a.v;
    }
}a[1000006];
deque<hd1>q;
void maxx(){
    q.clear();
    for(int i=1;i<=n;i++){
        while(q.size()>0&&q.back().v<=a[i].v) q.pop_back();
        q.push_back(a[i]);
        while(q.front().id<=i-k) q.pop_front();
        if(i>=k) printf("%d ",q.front());
    }
    cout<<endl;
}
void minn(){
    q.clear();
    for(int i=1;i<=n;i++){
        //只要队列里有元素,并且尾元素比待处理值大,
        //即表示尾元素已经不可能出场,所以出队。直到尾元素小于待处理值,满足"单调"。
        while(q.size()>0&&q.back().v>=a[i].v) q.pop_back();
        q.push_back(a[i]);//待处理值入队。
        while(q.front().id<=i-k) q.pop_front();//队首元素已经过时
        if(i>=k) printf("%d ",q.front());
    }
    cout<<endl;
}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();k=read();
    for(int i=1;i<=n;i++){a[i].v=read(),a[i].id=i;}
    minn();
    maxx();
    return 0;
}
举报

相关推荐

0 条评论