文章总数25祭+莫队略解

文章总数25祭+莫队略解
莫队,啥东东?
就是“排序巧妙优化复杂度,带来NOIP前的最后一丝宁静。几个活蹦乱跳的指针的跳跃次数,决定着莫队算法的优劣……”
所以,莫队几乎可以解决一切区间问题
比如
这道题
哈哈
其实是一道莫队入门题
我们先来想离线算法
如图:

如图!那么…
我们如何从第一次询问转移到第二次询问呐?
很简单
我们定两个指针:l和r
在这里插入图片描述
然后,就有好玩的事发生了!
两个区间的转移:
事实上是L指针往左/右移,R指针往左/右移
转移增么写?
定义一个数组happen[i]表示当前区间数字i出现的次数
则可以轻易地转移happen了。
但是题目不仅如此,还要我们计算它们的平方和
所以:
当每次移指针时,ans减去happen[last]2 加上happen[now]2 即可
恭喜你已经YY出了原始莫队!
但是复杂度仍是不堪入目
要是跳的太远,会还原成O(nm)级别的(暴力)
所以莫队的精髓来了:排序
怎么排?
要用到分块优化
定义b[i]表示第i个数所属块
定义u表示块数
u=sqrt(n)
b[i]=(i/u)+1
然后排序
如果两个区间的l在同块内,r小的排前面。
否则l小的排前面
为什么不以l为第一关键字,r为第二关键字排序内?
我也不知道
举个例子:
1 2
2 100000
3 3
自己体会一下即可
例题:
HH的项链
模板!
但是很遗憾,莫队只有80分
80pts:

#include<bits/stdc++.h>
using namespace std;
const int N=1000005; 
struct node{
    int l,r;
    int Rk;
    int ans;
}s[N];
int n,m;
int col[N];
int u;
int b[N];
int happen[5000005]={0};
int ans=0;
int l,r;
bool cmp(node x,node y){
    if(b[x.l]==b[y.l]) return x.r<y.r;
    return x.l<y.l;
}
bool kmp(node x,node y){
    return x.Rk<y.Rk;
}
int main(){
    scanf("%d",&n);
    u=sqrt(n);
    for(register int i=1;i<=n;i++) b[i]=(i/u)+1;//计算所属块 
    for(register int i=1;i<=n;i++) scanf("%d",&col[i]);
    scanf("%d",&m);
    for(register int i=1;i<=m;i++){
        scanf("%d%d",&s[i].l,&s[i].r);
        s[i].Rk=i;
    }
    sort(s+1,s+m+1,cmp);
    for(register int i=1;i<=m;i++){
        if(i==1){
            for(register int j=s[i].l;j<=s[i].r;j++){
                happen[col[j]]++;
                if(happen[col[j]]==1) ans++;
            }
            s[i].ans=ans;
        }
        else{
            while(l<s[i].l){
                l++;
                happen[col[l-1]]--;
                if(happen[col[l-1]]==0) ans--;
            }
            while(l>s[i].l){
                l--;
                happen[col[l]]++;
                if(happen[col[l]]==1) ans++;
            }
            while(r<s[i].r){
                r++;
                happen[col[r]]++;
                if(happen[col[r]]==1) ans++;
            }
            while(r>s[i].r){
                r--;
                happen[col[r+1]]--;
                if(happen[col[r+1]]==0) ans--;
            }
            s[i].ans=ans;
        }
        l=s[i].l,r=s[i].r;
    }
    sort(s+1,s+m+1,kmp);
    for(register int i=1;i<=m;i++){
        printf("%d\n",s[i].ans);
    }
    return 0;
} 

海星
P4137 Rmq Problem / mex
简单?
但是:
90:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000005;
struct node{
    int l,r;
    int ans;
    int Rk;
}s[N];
int n,m;
int col[N];
int b[N];
int u;
int happen[N]={0};
int l,r;
int ans=0;
bool cmp(node x,node y){
    if(b[x.l]==b[y.l]) return x.r<y.r;
    return x.l<y.l;
}
bool kmp(node x,node y){
    return x.Rk<y.Rk;
}
int main(){
    scanf("%d%d",&n,&m);
    u=sqrt(n);
    for(int i=1;i<=n;i++) b[i]=(i/u)+1;
    for(int i=1;i<=n;i++){
        scanf("%d",&col[i]);
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&s[i].l,&s[i].r);
        s[i].Rk=i;
    }
    sort(s+1,s+m+1,cmp);
    for(int i=1;i<=m;i++){
        if(i==1){
            for(int j=s[i].l;j<=s[i].r;j++){
                happen[col[j]]++;
                if(happen[col[j]]==1){
                    while(happen[ans]) ans++;
                }
            }
            l=s[i].l,r=s[i].r;
        }
        else{
            while(l<s[i].l){
                l++;
                happen[col[l-1]]--;
                if(happen[col[l-1]]==0&&col[l-1]<ans) ans=min(ans,col[l-1]);
            }
            while(l>s[i].l){
                l--;
                happen[col[l]]++;
                int ii=ans;
                while(happen[ii]) ii++;
                ans=ii;
            }
            while(r<s[i].r){
                r++;
                happen[col[r]]++;
                int ii=ans;
                while(happen[ii]) ii++;
                ans=ii;
            }
            while(r>s[i].r){
                r--;
                happen[col[r+1]]--;
                if(happen[col[r+1]]==0&&col[r+1]<ans) ans=min(ans,col[r+1]);
            }
        }
        s[i].ans=ans;
    }
    sort(s+1,s+m+1,kmp);
    for(int i=1;i<=m;i++){
        printf("%d\n",s[i].ans);
    }
    return 0;
} 

100

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000005;
struct node{
    int l,r;
    int ans;
    int Rk;
}s[N];
int n,m;
int col[N];
int b[N];
int u;
int happen[N]={0};
int l,r;
int ans=0;
bool cmp(node x,node y){
    if(b[x.l]==b[y.l]) return x.r<y.r;
    return x.l<y.l;
}
bool kmp(node x,node y){
    return x.Rk<y.Rk;
}
int main(){
    scanf("%d%d",&n,&m);
    u=sqrt(n);
    for(int i=1;i<=n;i++) b[i]=(i/u)+1;
    for(int i=1;i<=n;i++){
        scanf("%d",&col[i]);
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&s[i].l,&s[i].r);
        s[i].Rk=i;
    }
    sort(s+1,s+m+1,cmp);
    for(int i=1;i<=m;i++){
        if(i==1){
            for(int j=s[i].l;j<=s[i].r;j++){
                happen[col[j]]++;
                if(happen[col[j]]==1){
                    while(happen[ans]) ans++;
                }
            }
            l=s[i].l,r=s[i].r;
        }
        else{
            while(l<s[i].l){
                l++;
                happen[col[l-1]]--;
                if(happen[col[l-1]]==0&&col[l-1]<ans) ans=min(ans,col[l-1]);
            }
            while(l>s[i].l){
                l--;
                happen[col[l]]++;
                if(col[l]==ans) while(happen[ans]) ans++;
            }
            while(r<s[i].r){
                r++;
                happen[col[r]]++;
                if(col[r]==ans) while(happen[ans]) ans++;
            }
            while(r>s[i].r){
                r--;
                happen[col[r+1]]--;
                if(happen[col[r+1]]==0&&col[r+1]<ans) ans=min(ans,col[r+1]);
            }
        }
        s[i].ans=ans;
    }
    sort(s+1,s+m+1,kmp);
    for(int i=1;i<=m;i++){
        printf("%d\n",s[i].ans);
    }
    return 0;
}  

至为什么要加if(col[l]==ans)我至今不明
我太弱了,以至于不会带修莫队
但是:

THE END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以通过Spring Boot和Vue.js来按照数据库中的创建时间统计缴费总数,具体步骤如下: 1. 创建一个Spring Boot项目,并添加必要的依赖,如MySQL和Spring Data JPA依赖。 2. 定义一个实体类 `Payment` ,其中包含创建时间字段 `createdAt` 。 3. 创建一个Spring Data JPA的Repository,用于访问数据库。 ```java public interface PaymentRepository extends JpaRepository<Payment, Long> { @Query("SELECT DATE(p.createdAt) as date, COUNT(p.id) as total FROM Payment p GROUP BY DATE(p.createdAt)") List<Map<String, Object>> countPaymentsByCreatedAt(); } ``` 这个Repository定义了一个名为 `countPaymentsByCreatedAt()` 的方法,使用了JPQL语句来按照创建时间统计缴费总数,并返回一个包含日期和缴费总数的Map列表。 4. 创建一个Spring MVC的Controller,用于处理请求并返回数据给前端页面。 ```java @RestController public class PaymentController { @Autowired private PaymentRepository paymentRepository; @GetMapping("/payments") public List<Map<String, Object>> countPaymentsByCreatedAt() { return paymentRepository.countPaymentsByCreatedAt(); } } ``` 这个Controller定义了一个名为 `countPaymentsByCreatedAt()` 的GET请求处理方法,该方法调用了前面定义的Repository的方法,并将结果返回给前端页面。 5. 创建一个Vue.js的组件,用于显示缴费总数统计结果。 ```vue <template> <div> <h2>按日期统计缴费总数</h2> <table> <thead> <tr> <th>日期</th> <th>缴费总数</th> </tr> </thead> <tbody> <tr v-for="payment in payments" :key="payment.date"> <td>{{ payment.date }}</td> <td>{{ payment.total }}</td> </tr> </tbody> </table> </div> </template> <script> export default { data() { return { payments: [] }; }, mounted() { this.loadPayments(); }, methods: { loadPayments() { axios.get("/payments").then(response => { this.payments = response.data; }); } } }; </script> ``` 这个Vue.js组件包含一个表格,用于显示按日期统计的缴费总数。该组件在 `mounted()` 钩子函数中调用了后端的API接口 `/payments` ,并将结果保存在 `payments` 数据属性中,然后在模板中使用 `v-for` 指令来循环遍历 `payments` 数组,将日期和缴费总数显示在表格中。 6. 在前端页面中使用这个Vue.js组件,用于显示缴费总数统计结果。 ```html <div id="app"> <payment-statistics></payment-statistics> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script> Vue.component("payment-statistics", require("./components/PaymentStatistics.vue").default); new Vue({ el: "#app" }); </script> ``` 这个前端页面使用了Vue.js和Axios库,将 `PaymentStatistics` 组件注册为全局组件,并将其渲染到 `#app` 元素中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值