随笔 - 58,  文章 - 0,  评论 - 4,  阅读 - 3296

一、题目描述:

  给你一个长度为 n 的序列 a , 你需要回答 q 次询问。

     l  r  k 

  数据范围:1n,q5×105, 109val109


 二、解题思路:

  首先数据离散化,有效降低时间复杂度。

  明显是一个主席树板子题,但是今天学的是

  所以我们用  来做这个题,时间复杂度 O(nlog2n2)SPOJ 略微卡常。


 三、完整代码:

复制代码
 1 #include<map>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define N 100010
 5 using namespace std;
 6 map <int,int> rak;
 7 int n,m,tot;
 8 int t[N],a[N],sa[N],ans[N];
 9 struct Query{
10     int l,r,k,id;
11 }q[N*2],q1[N*2],q2[N*2];
12 int ask(int x)
13 {
14     int res=0;while(x)
15         res+=t[x],x-=x&(-x);
16     return res;
17 }
18 void upt(int x,int k)
19 {
20     while(x<=n)
21         t[x]+=k,x+=x&(-x);
22 }
23 //基本树状数组操作 
24 //solve(l,r,L,R)表示询问q[L]到q[R]的答案在l到r之间 
25 void solve(int l,int r,int L,int R)
26 {
27     if(l>r||L>R)    return ;
28     if(l==r)
29     {
30         for(int i=L;i<=R;i++)
31             ans[q[i].id]=l;
32         return ;
33     }
34     int cnt1=0,cnt2=0,mid=(l+r)>>1;
35     //注意到数组总是在前面,询问总是在后面,不用担心 
36     for(int i=L;i<=R;i++)
37     {
38         if(!q[i].id){
39             if(q[i].l>mid) q2[++cnt2]=q[i];
40             else upt(q[i].r,1),q1[++cnt1]=q[i];
41         }else{
42             int tmp=ask(q[i].r)-ask(q[i].l-1);
43             if(q[i].k<=tmp)    q1[++cnt1]=q[i];
44             else q[i].k-=tmp,q2[++cnt2]=q[i];
45             //这里细节比较多,要细细的想一下 
46         }
47     }
48     for(int i=1;i<=cnt1;i++)
49         if(!q1[i].id)
50             upt(q1[i].r,-1);
51     //高效清空树状数组 
52     for(int i=1;i<=cnt1;i++)
53         q[L+i-1]=q1[i];
54     for(int i=1;i<=cnt2;i++)
55         q[L+i+cnt1-1]=q2[i];
56     //这是节约空间的好办法,大概可以应用到 FFT 中 
57     solve(l,mid,L,L+cnt1-1);
58     solve(mid+1,r,L+cnt1,R);
59     //分治,注意范围 
60 }
61 int main()
62 {
63     ios::sync_with_stdio(false);
64     cin.tie(0);cout.tie(0);
65     cin>>n>>m;
66     for(int i=1;i<=n;i++)
67         cin>>q[i].l,q[i].r=i,a[i]=q[i].l;
68     sort(a+1,a+1+n);
69     for(int i=1;i<=n;i++)
70         if(i==1||a[i]!=a[i-1])
71             rak[a[i]]=++tot,sa[tot]=a[i];
72     for(int i=1;i<=n;i++)
73         q[i].l=rak[q[i].l];
74     //离散化 
75     for(int i=1,j=i+n;i<=m;i++,j++)
76         cin>>q[j].l>>q[j].r>>q[j].k,q[j].id=i;
77     solve(1,tot,1,n+m);
78     for(int i=1;i<=m;i++)
79         cout<<sa[ans[i]]<<'\n';
80     //注意答案还原 
81     return 0;
82 }
复制代码

四、写题心得:

  嗨哟,终于把 搞懂了,收获经验如下:

  1=>Exp++!

  2=>Exp++

posted on   trh0630  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示