主席树专题

题目描述

最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行),其优先级为Pi。同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同。调度系统会经常向查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个)的优先级之和是多少。特别的,如果Ki大于第Xi秒正在运行的任务总数,则直接回答第Xi秒正在运行的任务优先级之和。上述所有参数均为整数,时间的范围在1到n之间(包含1和n)。

输入格式

输入文件第一行包含两个空格分开的正整数m和n,分别表示任务总数和时间范围。接下来m行,每行包含三个空格分开的正整数Si、Ei和Pi(Si<=Ei),描述一个任务。接下来n行,每行包含四个空格分开的整数Xi、Ai、Bi和Ci,描述一次查询。查询的参数Ki需要由公式 Ki=1+(Ai*Pre+Bi) mod Ci计算得到。其中Pre表示上一次查询的结果,对于第一次查询,Pre=1。

输出格式

输出共n行,每行一个整数,表示查询结果。

输入输出样例

输入 #1复制

4 3
1 2 6
2 3 3
1 3 2
3 3 4
3 1 3 2
1 1 3 4
2 2 4 3

输出 #1复制

2
8
11

说明/提示

样例解释

K1 = (1*1+3)%2+1 = 1

K2 = (1*2+3)%4+1 = 2

K3 = (2*8+4)%3+1 = 3

对于100%的数据,1<=m,n,Si,Ei,Ci<=100000,0<=Ai,Bi<=100000,1<=Pi<=10000000,Xi为1到n的一个排列

题解:给一段区间加上某个数,自然可以想到差分数组的做法。为何一个区间内优先级的个数和一个区间优先级的加和。

#include <bits/stdc++.h>
#define ll long long
#define inf 1e15
#define INF 0x3f3f3f3f
#define mod 1000000007
using namespace std;
#define maxx 7000010
#define maxn 200010
struct node
{
    int ls,rs;
    ll sc,sum;
}tree[maxn<<6];
int root[maxn];
int tot=0;
vector<pair<int,int> >g1[maxn];
vector<pair<int,int> >g2[maxn];
int update(int rt,int l,int r,int va,int f)
{
    tree[++tot]=tree[rt];
    int now=tot;
    tree[now].sc+=f;
    tree[now].sum=tree[now].sum+va*f;
    if(l==r) return now;
    int mid=(l+r)>>1;
    if(mid>=va)
    {
        tree[now].ls=update(tree[now].ls,l,mid,va,f);
    }
    else tree[now].rs=update(tree[now].rs,mid+1,r,va,f);
    return now;
}
ll qurey(int rt,ll Kth,int l,int r)
{
    if(l==r)
    {
        return tree[rt].sum/tree[rt].sc*Kth;
    }
    int mid=(l+r)>>1;
    if(tree[tree[rt].ls].sc>=Kth)
    {
        return qurey(tree[rt].ls,Kth,l,mid);
    }
    else return tree[tree[rt].ls].sum+qurey(tree[rt].rs,Kth-tree[tree[rt].ls].sc,mid+1,r);
}
int main(){
    int n,m;
    int mf=0;
    scanf("%d %d",&m,&n);
    while(m--)
    {
        int si,ei,pi;
        scanf("%d %d %d",&si,&ei,&pi);
        g1[si].push_back(make_pair(pi,1));
        g2[ei+1].push_back(make_pair(pi,-1));
        mf=max(mf,pi);
    }
    for(int i=1;i<=n;i++)
    {
        root[i]=root[i-1];
        for(auto v: g1[i])
        {
            root[i]=update(root[i],1,mf,v.first,v.second);
        }
        for(auto v: g2[i])
        {
            root[i]=update(root[i],1,mf,v.first,v.second);
        }
    }
    ll pre=1;
    while(n--)
    {
        int xi,ai,bi,ci;
        ll ki;
        scanf("%d %d %d %d",&xi,&ai,&bi,&ci);
        ki=1ll+(1ll*ai*pre+bi*1ll)%(ci*1ll);
        ll ans;
        if(ki>=tree[root[xi]].sc)//不加这个判断会RE
        {
            ans=tree[root[xi]].sum;
        }
        else ans=qurey(root[xi],ki,1,mf);
        printf("%lld\n",ans);
        pre=ans;
    }
    return 0;
}

POJ 2761

Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but not the dogs, so Jiajia use a special way to feed the dogs. At lunchtime, the dogs will stand on one line, numbered from 1 to n, the leftmost one is 1, the second one is 2, and so on. In each feeding, Jiajia choose an inteval[i,j], select the k-th pretty dog to feed. Of course Jiajia has his own way of deciding the pretty value of each dog. It should be noted that Jiajia do not want to feed any position too much, because it may cause some death of dogs. If so, Wind will be angry and the aftereffect will be serious. Hence any feeding inteval will not contain another completely, though the intervals may intersect with each other.

Your task is to help Jiajia calculate which dog ate the food after each feeding.

Input

The first line contains n and m, indicates the number of dogs and the number of feedings.

The second line contains n integers, describe the pretty value of each dog from left to right. You should notice that the dog with lower pretty value is prettier.

Each of following m lines contain three integer i,j,k, it means that Jiajia feed the k-th pretty dog in this feeding.

You can assume that n<100001 and m<50001.

Output

Output file has m lines. The i-th line should contain the pretty value of the dog who got the food in the i-th feeding.

Sample Input

7 2
1 5 2 6 3 7 4
1 5 3
2 7 1

模板题:查询区间第K小的数。

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <cstring>
#include <iostream>
//#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=100010;
struct node
{
    int ls,rs;
    int va;
}tree[100010*30];
int tot,len;
int a[maxn];
int t[maxn];
int root[maxn];
void ini_hash(int n)
{
    for(int i=1;i<=n;i++)
    {
        t[i]=a[i];
    }
    sort(t+1,t+n+1);
    len=unique(t+1,t+1+n)-t-1;
}
int getpos(int x)
{
    return lower_bound(t+1,t+1+len,x)-t;
}
int update(int rt,int l,int r,int p,int v)
{
    int now=++tot;
    tree[now]=tree[rt];
    tree[now].va+=v;
    if(l==r) return now;
    int mid=(l+r)>>1;
    if(mid>=p)
    {
        tree[now].ls=update(tree[now].ls,l,mid,p,v);
    }
    else tree[now].rs=update(tree[now].rs,mid+1,r,p,v);
    return now;
}
int query(int x,int y,int l,int r,int kth)
{
    if(l==r)
    {
        return l;
    }
    int mid=(l+r)>>1;
    if(tree[tree[y].ls].va-tree[tree[x].ls].va>=kth)
    {
        return query(tree[x].ls,tree[y].ls,l,mid,kth);
    }
    else
    {
        return query(tree[x].rs,tree[y].rs,mid+1,r,kth-(tree[tree[y].ls].va-tree[tree[x].ls].va));
    }
}

int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    ini_hash(n);//离散化
    for(int i=1;i<=n;i++)
    {
        root[i]=update(root[i-1],1,len,getpos(a[i]),1);
    }
    for(int i=1;i<=m;i++)
    {
        int x,y,kth;
        scanf("%d %d %d",&x,&y,&kth);
        printf("%d\n",t[query(root[x-1],root[y],1,len,kth)]);
    }
    return 0;
}

查询区间某个值域范围内的数

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <cstring>
#include <iostream>
//#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=100010;
struct node
{
    int ls,rs;
    int va;
}tree[100010*30];
int tot,len;
int a[maxn];
int t[maxn];
int root[maxn];
void ini_hash(int n)
{
    for(int i=1;i<=n;i++)
    {
        t[i]=a[i];
    }
    sort(t+1,t+n+1);
    len=unique(t+1,t+1+n)-t-1;
}
int getpos(int x)
{
    return lower_bound(t+1,t+1+len,x)-t;
}
int update(int rt,int l,int r,int p,int v)
{
    int now=++tot;
    tree[now]=tree[rt];
    tree[now].va+=v;
    if(l==r) return now;
    int mid=(l+r)>>1;
    if(mid>=p)
    {
        tree[now].ls=update(tree[now].ls,l,mid,p,v);
    }
    else tree[now].rs=update(tree[now].rs,mid+1,r,p,v);
    return now;
}
int query(int x,int y,int l,int r,int L,int R)
{
    if(l>=L&&R>=r)
    {
        return tree[y].va-tree[x].va;
    }
    int mid=(l+r)>>1;
    int ans=0;
    if(mid>=L) ans+=query(tree[x].ls,tree[y].ls,l,mid,L,R);
    if(mid<R) ans+=query(tree[x].rs,tree[y].rs,mid+1,r,L,R);
    return ans;
}

int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    ini_hash(n);
    for(int i=1;i<=n;i++)
    {
        root[i]=update(root[i-1],1,len,getpos(a[i]),1);
    }
    for(int i=1;i<=m;i++)
    {
        int l,r;
        int x,y,kth;
        scanf("%d %d %d %d",&l,&r,&x,&y);//l~r区间内值的范围在x~y的数字有多少个
        int res=query(root[l-1],root[r],1,len,getpos(x),getpos(y));
        printf("%d\n",res);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值