Coder HDU

Coder HDU - 4288

题意:你有n次操作,每次可以往集合里插入元素,删除元素,然后如果是求和操作的话,是求升序排序的情况下,pos%5==3的位置的数之和。

思路:因为要开权值线段树数很大,所以先把操作离线把要用到的数都离散化了,然后线段树维护的是区间数的个数num和区间位置%5==i的位置的数之和sum[i],我们最后查询的时候要的是根节点的sum[3],这题的关键就是这个pushup里的更新sum【i】值。

for(int i=0;i<=4;i++)
        sum[rt][i]=sum[ls][i]+sum[rs][((i-num[ls])%5+5)%5];

因为求根节点的sum[3]的时候说不定用的是右儿子的sum[0,1,2,3,4]里的哪个,所有对节点都要维护sum[0~4],然后sum[rt][i]要直接加上左儿子的sum[ls][i]是毋庸置疑的,关键是要找到rs节点对应区间里的数放到rt节点区间里时位置%5==i的位置的数之和是多少假设这个位置是pos,那么有(ls.num+pos)%5==i,我们要的就是满足条件的pos位置的数之和,然后有

同余式相加:若a≡b(mod m),c≡d(mod m),则a+c≡b+d(mod m); 减法也成立
同余式相乘:若a≡b(mod m),c≡d(mod m),则ac≡bd(mod m)。

所有可以得到pos同余(i-ls.num) 在mod5情况下,那么就有pos%5==(i-ls.num)%5,所以要的就是右儿子的sum[(i-ls.num)%5]。由于pos%5==(i-ls.num)%5这个是数学上相等,到了c++里面可以就不一定相等了因为数学里(-20)%11==2,但是c++里(-20)%11==-9,所以写代码的时候还要考虑(i-ls.num)%5为负数的情况,那么((i-ls.num)%5+5)%5就可以避免负数的情况了,所以应该是加sum[((i-num[ls])%5+5)%5]。

#include<stdio.h>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define ll __int64
#define fuck(x) cout<<#x<<"     "<<x<<endl;
const int maxn=1e5+20;
int d[4][2]={1,0,-1,0,0,1,0,-1};
int num[maxn<<2],n,vcnt;
ll sum[maxn<<2][5],lsh[maxn];
struct node
{
    char op[10];
    ll val;
}q[maxn];
inline int getid(ll x)
{
    return lower_bound(lsh+1,lsh+vcnt+1,x)-lsh;
}
void pushup(int rt)
{
    num[rt]=num[ls]+num[rs];
    for(int i=0;i<=4;i++)
        sum[rt][i]=sum[ls][i]+sum[rs][((i-num[ls])%5+5)%5];
}
void update(int rt,int L,int R,int pos,int val)
{
    if(L==R)
    {
        if(val==1)
        {
            num[rt]=1;
            sum[rt][1]=1LL*lsh[pos];
        }
        else
        {
            num[rt]=0;
            sum[rt][1]=0LL;
        }
        return ;
    }
    int mid=(L+R)>>1;
    if(pos<=mid)
        update(ls,L,mid,pos,val);
    else
        update(rs,mid+1,R,pos,val);
    pushup(rt);
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        vcnt=0;
        memset(num,0,sizeof(num));
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
        {
            scanf("%s",q[i].op);
            if(q[i].op[0]=='a'||q[i].op[0]=='d')
                scanf("%I64d",&(q[i].val)),lsh[++vcnt]=q[i].val;
        }
        sort(lsh+1,lsh+vcnt+1);
        vcnt=unique(lsh+1,lsh+vcnt+1)-lsh-1;
        for(int i=1;i<=n;i++)
            if(q[i].op[0]=='a')
                update(1,1,vcnt,getid(q[i].val),1);
            else
                if(q[i].op[0]=='d')
                    update(1,1,vcnt,getid(q[i].val),0);
                else
                    printf("%I64d
",sum[1][3]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/eason9906/p/11754747.html