11.3考试爆炸记

原地爆炸
(1)区间
n2 预处理大暴力

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<map>
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
#define stan 8888
int tot,nxt[stan],first[stan],goal[stan];
int n,q,a[stan];
map<int,int>id;
int f1[stan],f2[stan],f[stan],sze[stan<<1],vis[stan<<1],lef,cnt,cnt1,cnt2,cnt3;
int ans[stan][stan],spi[stan];
int tota,pos1,pos2,x,y,now;
void addedge(int a,int b){
    nxt[++tot]=first[a];first[a]=tot;goal[tot]=b;
    return ;
}
signed main(){
    n=read();q=read();
    for(register int i=1;i<=n;++i){
        a[i]=read();
        if(!id[a[i]])
            id[a[i]]=++cnt;
        a[i]=id[a[i]];
    }
    for(register int i=n;i;--i)
        addedge(a[i],i);
    for(register int i=1;i<=cnt;++i)
        for(register int j=i+1;j<=cnt;++j){
            ++tota;
            cnt1=0;cnt2=0;cnt3=0;
            for(int p=first[i];p;p=nxt[p])
                f1[++cnt1]=goal[p];
            for(int p=first[j];p;p=nxt[p])
                f2[++cnt2]=goal[p];
            cnt3=cnt1+cnt2;
            pos1=1;pos2=1;
            for(int k=1;k<=cnt3;++k){
                if(pos2>cnt2||(pos1<=cnt1&&f1[pos1]<f2[pos2]))
                    f[k]=f1[pos1++];
                else 
                    f[k]=f2[pos2++];
            }
            now=8000;
            vis[now]=tota;
            sze[now]=f[1];
            ans[i][j]=f[1]*(f[1]-1)/2;
            f[cnt3+1]=n+1;
            for(int k=1;k<=cnt3;++k){
                if(a[f[k]]==i) ++now;
                else --now;
                if(vis[now]<tota){
                    sze[now]=0;
                    vis[now]=tota;
                }
                ans[i][j]=ans[i][j]+(f[k+1]-f[k])*sze[now]+(f[k+1]-f[k])*(f[k+1]-f[k]-1)/2;
                sze[now]=sze[now]+f[k+1]-f[k];
            }
            ans[j][i]=ans[i][j];
        }
    for(register int i=1;i<=cnt;++i){
        spi[i]=0;
        lef=0;
        for(register int p=first[i];p;p=nxt[p]){
            spi[i]=spi[i]+(goal[p]-lef)*(goal[p]-lef-1)/2;
            lef=goal[p];
        }
        spi[i]=spi[i]+(n-lef)*(n-lef+1)/2;
    }
    for(register int i=1;i<=q;++i){
        x=read();y=read();
        x=id[x];y=id[y];
        if((!x&&!y)||(x==y))
            write((n+1)*n/2),puts("");
        else if(!x||!y) 
            write(spi[x^y]),puts("");
        else
            write(ans[x][y]),puts("");
    }
    return 0;
}

(2)排列
线段树求最小值

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
#define stan 111111
int n,num[stan],a[stan],sum[stan],pos[stan<<2],mini[stan<<3],tag[stan<<3];
void build(int k,int l,int r){
    if(l==r){
        mini[k]=l-a[l];
        pos[k]=l;
        return ;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    mini[k]=min(mini[k<<1],mini[k<<1|1]);
    if(mini[k]==mini[k<<1|1])
        pos[k]=pos[k<<1|1];
    else
        pos[k]=pos[k<<1];
    return ;
}
void addtag(int k,int l,int r,int x,int y){
    tag[k<<1]+=tag[k];mini[k<<1]-=tag[k];
    tag[k<<1|1]+=tag[k];mini[k<<1|1]-=tag[k];
    tag[k]=0;
    if(x<=l&&r<=y){
        --mini[k];
        ++tag[k];
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid) addtag(k<<1,l,mid,x,y);
    if(y>mid) addtag(k<<1|1,mid+1,r,x,y);
    mini[k]=min(mini[k<<1],mini[k<<1|1]);
    if(mini[k]==mini[k<<1|1])
        pos[k]=pos[k<<1|1];
    else
        pos[k]=pos[k<<1];
    return ;
}
void change(int k,int l,int r,int x,int d){
    tag[k<<1]+=tag[k];mini[k<<1]-=tag[k];
    tag[k<<1|1]+=tag[k];mini[k<<1|1]-=tag[k];
    tag[k]=0;
    if(l==r){
        mini[k]=d;
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid) change(k<<1,l,mid,x,d);
    else change(k<<1|1,mid+1,r,x,d);
    mini[k]=min(mini[k<<1],mini[k<<1|1]);
    if(mini[k]==mini[k<<1|1])
        pos[k]=pos[k<<1|1];
    else
        pos[k]=pos[k<<1];
    return ;
}
signed main(){
    n=read();
    for(int i=1;i<=n;++i)
        sum[i]=read();
    for(int i=1;i<=n;++i)
        a[i]=sum[i]-sum[i-1];
    if(n<=1000){
        for(int i=1;i<=n;++i)
            for(int j=n;j;--j)
                if(a[j]==j-1){
                    num[j]=i;
                    for(int k=j;k<=n;++k)
                        ++a[k];
                    break;
                }
    }else{
        build(1,1,n);
        for(int i=1;i<=n;++i){
            int x=pos[1];
            num[x]=i;
            change(1,1,n,x,n+2);
            if(x<n)
                addtag(1,1,n,x+1,n);
        }   
    }
    for(int i=1;i<=n;++i){
        write(num[i]);putchar(' ');
    }
    return 0;
}

(3)边的处理
分治处理DP中点
复杂度?
O(mlogmn2+nq)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<map>
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x){buf[++buf[0]]=x%10,x/=10;}
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
#define stan 22222
#define sten 222222
#define stin 33
struct edg{
    int x,y,r,c;
}edge[stan];
struct query{
    int x,y,l,r,id;
}que[sten],temp[sten];
int lef[stan][stin][stin],righ[stan][stin][stin],ans[sten],tmp,posl,posr;
int n,m,q;
void solve(int le,int re,int lq,int rq){
    if(lq>rq) return;
    if(le==re){
        for(int i=lq;i<=rq;++i){
            if(que[i].x!=que[i].y){
                if(que[i].x==edge[le].x&&que[i].y==edge[le].y)
                    ans[que[i].id]=edge[le].c;
                else
                    ans[que[i].id]=-1;
            }else{
                ans[que[i].id]=999999999;
                if(que[i].x==edge[le].x&&que[i].y==edge[le].y)
                    ans[que[i].id]=edge[le].c;
                ans[que[i].id]=min(ans[que[i].id],edge[le].r);
            }
        }
        return ;
    }else{
        int mid=le+re>>1;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                lef[mid+1][i][j]=999999999;
                righ[mid][i][j]=999999999;
            }
            lef[mid+1][i][i]=0;
            righ[mid][i][i]=0;
        }
        for(int i=mid;i>=le;--i){
            for(int j=1;j<=n;++j)
                for(int k=1;k<=n;++k)
                    lef[i][j][k]=lef[i+1][j][k]+edge[i].r;
            for(int j=1;j<=n;++j){
                if(lef[i+1][j][edge[i].x]<999999999)
                    lef[i][j][edge[i].y]=min(lef[i][j][edge[i].y],lef[i+1][j][edge[i].x]+edge[i].c);
                if(lef[i+1][j][edge[i].y]<999999999)
                    lef[i][j][edge[i].x]=min(lef[i][j][edge[i].x],lef[i+1][j][edge[i].y]+edge[i].c);
            }
        }
        for(int i=mid+1;i<=re;++i){
            for(int j=1;j<=n;++j)
                for(int k=1;k<=n;++k)
                    righ[i][j][k]=righ[i-1][j][k]+edge[i].r;
            for(int j=1;j<=n;++j){
                if(righ[i-1][j][edge[i].x]<999999999)
                    righ[i][j][edge[i].y]=min(righ[i][j][edge[i].y],righ[i-1][j][edge[i].x]+edge[i].c);
                if(righ[i-1][j][edge[i].y]<999999999)
                    righ[i][j][edge[i].x]=min(righ[i][j][edge[i].x],righ[i-1][j][edge[i].y]+edge[i].c);
            }
        }
        for(int i=lq;i<=rq;++i)
            if(que[i].l<=mid&&que[i].r>mid){
                tmp=999999999;
                for(int j=1;j<=n;++j)
                    tmp=min(tmp,lef[que[i].l][j][que[i].x]+righ[que[i].r][j][que[i].y]);
                if(tmp>=999999999)
                    ans[que[i].id]=-1;
                else
                    ans[que[i].id]=tmp;
            }
        for(int i=lq;i<=rq;++i)
            temp[i]=que[i];
        int posl=lq,posr=rq;
        for(int i=lq;i<=rq;++i){
            if(temp[i].r<=mid) que[posl++]=temp[i];
            if(temp[i].l>mid) que[posr--]=temp[i];
        }
        solve(le,mid,lq,posl-1);
        solve(mid+1,re,posr+1,rq);
    }
    return ;
}
signed main(){
    n=read();m=read();q=read();
    for(int i=1;i<=m;++i){
        edge[i].x=read();
        edge[i].y=read();
        edge[i].c=read();
        edge[i].r=read();
    }
    for(int i=1;i<=q;++i){
        que[i].x=read();
        que[i].y=read();
        que[i].l=read();
        que[i].r=read();
        que[i].id=i;
    }
    solve(1,m,1,q);
    for(int i=1;i<=q;++i){
        write(ans[i]);
        puts("");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值