Informatics Training

题目描述

这里写图片描述

数据结构

对每个小组用两个数据结构维护,分别维护体力和刷题量。
对于合并的操作,可以启发式合并。
单个修改直接在对应的数据结构里改。
小组修改可以通过打tag实现,这个tag只有在这个小组被并进另一个小组的时候才下传。注意这个tag是永久化的,因此并进另一个小组时,要把它们对另一个小组的tag进行反作用。
淘汰人可以在对应数据结构进行修改。
为了方便做考核操作,每个小组维护出刷题量最小值,再用一个大数据结构维护出所有中的最小值。
那么这就有一些细节了,每次对小组进行更改时也要顺便来维护这个大数据结构。
每次先找到最小值,然后不断淘汰人,每次在大数据结构中的第一个小组中淘汰最小的人,一直做到大数据结构查出最小的不等于最小值。
对于编号存在情况还需要使用一个数据结构。
对于查询的话,每个小组都要保存个数和和,在各种操作中都要注意维护。
这个数据结构使用set会轻松许多,但是不会跑的很快。
这就很丧病了QAQ

#include<cstdio>
#include<algorithm>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=300000+10;
struct dong{
    int x;
    ll y;
    friend bool operator <(dong a,dong b){
        return a.y<b.y||a.y==b.y&&a.x<b.x;
    }
} zlt;
multiset<int> id;
multiset<int>::iterator it;
multiset<dong> s,c[maxn],d[maxn];
int fa[maxn],size[maxn],belong[maxn];
ll a[maxn],b[maxn],sb[maxn],ad[maxn],mi[maxn],sum[maxn],wdc;
int sta[80];
int i,j,k,l,r,t,n,m,tot,top,cnt,num,ans,mx;
char ch;
int read(){
    int 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*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
char get(){
    char ch=getchar();
    while (ch!='J'&&ch!='P'&&ch!='D'&&ch!='E'&&ch!='M'&&ch!='C'&&ch!='T'&&ch!='Q') ch=getchar();
    return ch;
}
int getfa(int x){
    return fa[x]?fa[x]=getfa(fa[x]):x;
}
void work(int x){
    zlt.x=x;zlt.y=mi[x];
    if (s.find(zlt)==s.end()) return;
    s.erase(s.find(zlt));
    if (d[x].begin()==d[x].end()) return;
    mi[x]=(*(d[x].begin())).y+ad[x];
    zlt.x=x;zlt.y=mi[x];
    s.insert(zlt);
}
void del(int x){
    id.erase(id.find(x));
    int y=getfa(x);
    zlt.x=x;zlt.y=a[x];
    c[y].erase(c[y].find(zlt));
    zlt.x=x;zlt.y=b[x];
    d[y].erase(d[y].find(zlt));
    work(y);
    size[y]--;
    sum[y]-=b[x];
    sum[y]-=ad[y];
    num--;
}
void merge(int x,int y){
    x=getfa(x),y=getfa(y);
    if (x==y) return;
    if (size[x]>size[y]) swap(x,y);
    while (!c[x].empty()){
        zlt=*(c[x].begin());
        zlt.y-=sb[x];
        zlt.y+=sb[y];
        a[zlt.x]=zlt.y;
        c[y].insert(zlt);
        c[x].erase(c[x].begin());
    }
    while (!d[x].empty()){
        zlt=*(d[x].begin());
        zlt.y+=ad[x];
        zlt.y-=ad[y];
        b[zlt.x]=zlt.y;
        d[y].insert(zlt);
        d[x].erase(d[x].begin());
    }
    zlt.x=x;zlt.y=mi[x];
    s.erase(s.find(zlt));
    work(y);
    size[y]+=size[x];
    sum[y]+=sum[x];
    fa[x]=y;
}
void write(ll x){
    if (!x){
        putchar('0');
        return;
    }
    top=0;
    while (x){
        sta[++top]=x%10;
        x/=10;
    }
    while (top) putchar('0'+sta[top--]);
}
int main(){
    freopen("training.in","r",stdin);freopen("training.out","w",stdout);
    m=read();
    while (m--){
        ch=get();
        if (ch=='J'){
            ++tot;
            ++num;
            a[tot]=read();b[tot]=read();
            id.insert(tot);
            mi[tot]=b[tot];
            zlt.x=tot;zlt.y=mi[tot];
            s.insert(zlt);
            d[tot].insert(zlt);
            zlt.x=tot;zlt.y=a[tot];
            c[tot].insert(zlt);
            size[tot]=1;
            sum[tot]=b[tot];
        }
        else if (ch=='P'){
            j=read();k=read();l=read();
            if (id.find(j)==id.end()) continue;
            r=getfa(j);
            if (a[j]-sb[r]<=k){
                del(j);
                continue;
            }
            zlt.x=j;zlt.y=a[j];
            c[r].erase(c[r].find(zlt));
            a[j]-=(ll)k;
            zlt.x=j;zlt.y=a[j];
            c[r].insert(zlt);
            zlt.x=j;zlt.y=b[j];
            d[r].erase(d[r].find(zlt));
            b[j]+=(ll)l;
            zlt.x=j;zlt.y=b[j];
            d[r].insert(zlt);
            sum[r]+=(ll)l;
            work(r);
        }
        else if (ch=='D'){
            j=read();k=read();l=read();
            if (id.find(j)==id.end()) continue;
            r=getfa(j);
            sb[r]+=(ll)k;ad[r]+=(ll)l;
            sum[r]+=(ll)l*size[r];
            while (1){
                if (c[r].begin()==c[r].end()) break;
                t=(*(c[r].begin())).x;
                if (a[t]-sb[r]<=0) del(t);else break;
            }
            work(r);
        }
        else if (ch=='E'){
            j=read();
            if (id.find(j)==id.end()) continue;
            del(j);
        }
        else if (ch=='M'){
            j=read();k=read();
            if (id.find(j)==id.end()) continue;
            if (id.find(k)==id.end()) continue;
            merge(j,k);
        }
        else if (ch=='C'){
            if (!num) continue;
            j=*id.begin();
            it=id.end();
            --it;
            k=*it;
            merge(j,k);
        }
        else if (ch=='T'){
            if (!num) continue;
            wdc=(*s.begin()).y;
            while (1){
                if (s.begin()==s.end()) break;
                t=(*s.begin()).y;
                if (t!=wdc) break;
                t=(*s.begin()).x;
                t=(*d[t].begin()).x;
                del(t);
            }
        }
        else{
            j=read();
            if (id.find(j)==id.end()) continue;
            j=getfa(j);
            write(size[j]);putchar(' ');
            write(sum[j]);putchar('\n');
            //printf("%d %lld\n",size[j],sum[j]);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值