zoukankan      html  css  js  c++  java
  • P3168 [CQOI2015]任务查询系统

    传送门

    求前 $K$ 小的数的和,考虑主席树

    但是如果每个时间都暴力插入显然会GG

    发现每个任务都是区间,查询是单点查询

    所以考虑维护差分数组

    直接用主席树维护差分数组,因为同一时间差分可能有多次修改,所以要把当前修改全部搞完才算当前时间的线段树

    询问就在相应时间点的线段树上走

    具体看代码理解吧

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e5+7,M=2e7+7;
    int n,m;
    
    int rt[N],L[M],R[M],sz[M],cnt;
    ll S[M];//注意long long!
    int val,K;
    ll res;//long long !
    void ins(int &o,int l,int r,int pre)//插入
    {
        o=++cnt; S[o]=S[pre]+val; sz[o]=sz[pre]+(val>0 ? 1 : -1);
        //注意我们维护的是差分数组,要根据val的正负来判断加还是删
        if(l==r) return;
        int mid=l+r>>1;
        if(abs(val)<=mid) ins(L[o],l,mid,L[pre]),R[o]=R[pre];//注意val要取绝对值
        else ins(R[o],mid+1,r,R[pre]),L[o]=L[pre];
    }
    void query(int o,int l,int r)
    {
        if(l==r) { res+=l*K; return; }
        int mid=l+r>>1;
        if(sz[L[o]]<K) { K-=sz[L[o]]; res+=S[L[o]]; query(R[o],mid+1,r); }
        //注意当前的位置是[1,pos]为闭区间所以是sz[L[o]] '<' K不是 '<=',(upd:好像也可以,但是最好还是注意一下变量的意义qwq)
        else query(L[o],l,mid);
    }
    
    int p[N],tot;
    vector <int> V[N];//维护一个时间点的差分操作
    int main()
    {
        int a,b,c,mx=0;
        n=read(),m=read();
        for(int i=1;i<=n;i++)
        {
            a=read(),b=read(),c=read(); mx=max(mx,c);
            V[a].push_back(c); V[b+1].push_back(-c);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=V[i].size()-1;j>=0;j--)//要先处理所有操作
                tot++,val=V[i][j],ins(rt[tot],1,mx,rt[tot-1]);
            p[i]=tot;//最后才算当前时间点的线段树
        }
        int x; ll las=1;//初始las=1,long long !
        while(m--)
        {
            x=read(),a=read(),b=read(),c=read();
            x=rt[p[x]]; K=1+(las*a+b)%c;
            if(sz[x]<=K) { printf("%lld
    ",S[x]); las=S[x]; continue; }//特判
            res=0; query(x,1,mx); printf("%lld
    ",res); las=res;//输出要long long!
        }
    }
  • 相关阅读:
    Linux Shell常用shell命令
    shell ls
    [转]推荐一些不错的计算机书籍
    What does it mean when you assign [super init] to self?
    保存,读取与多任务处理
    程序媛去过的地方
    读取pcap文件,过滤非tcp包,获取IP及tcp端口信息
    IM实现联系人及联系人分组的数据库设计
    【原创】校园网用户,1个账号2个笔记本上网,Ad hoc无线连网应用
    【openfire插件开发】群组聊天中的中介者模式
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10596178.html
Copyright © 2011-2022 走看看